Module: RMExtensions::ObjectExtensions::Util
- Defined in:
- lib/motion/util.rb
Instance Method Summary collapse
-
#rmext_assert_main_thread! ⇒ Object
Raises an exception when called from a thread other than the main thread.
- #rmext_assign_debug_labels_to_ivars! ⇒ Object
-
#rmext_block_on_main_q(block, *args) ⇒ Object
call the block immediately if called on the main thread with the given args, otherwise call it async on the main queue.
-
#rmext_debounce_on_next_runloop(unique_id, run_immediately, &block) ⇒ Object
takes a unique_id, run_immediately bool, and block if run_immediately is true, the block is executed immediately and not counted on the next run loop, the block will be called IF it has been counted at least once.
- #rmext_debounce_selector_on_next_runloop(selector, run_immediately) ⇒ Object
-
#rmext_debounced(method_name, seconds, *args) ⇒ Object
more typical debouncing behavior.
-
#rmext_dispatch__send__(*args) ⇒ Object
used internally by ‘rmext_debounced`.
-
#rmext_inline_or_on_main_q(&block) ⇒ Object
call the block immediately if called on the main thread, otherwise call it async on the main queue.
-
#rmext_ivar(*args) ⇒ Object
Shortcut to instance_variable_get and instance_variable_get: 1 arg for instance_variable_get 2 args for instance_variable_set.
- #rmext_nil_instance_variables! ⇒ Object
- #rmext_object_desc ⇒ Object
Instance Method Details
#rmext_assert_main_thread! ⇒ Object
Raises an exception when called from a thread other than the main thread. Good for development and experimenting.
153 154 155 |
# File 'lib/motion/util.rb', line 153 def rmext_assert_main_thread! raise "This method must be called on the main thread." unless NSThread.currentThread.isMainThread end |
#rmext_assign_debug_labels_to_ivars! ⇒ Object
178 179 180 181 182 183 184 185 |
# File 'lib/motion/util.rb', line 178 def rmext_assign_debug_labels_to_ivars! ivars = [] + instance_variables while ivar = ivars.pop val = instance_variable_get(ivar) val.rmext_ivar(:debug_label, ivar) end true end |
#rmext_block_on_main_q(block, *args) ⇒ Object
call the block immediately if called on the main thread with the given args, otherwise call it async on the main queue. silently ignores nil blocks to avoid if !block.nil? checks, useful for async callbacks that optionally take a callback
201 202 203 204 205 206 207 |
# File 'lib/motion/util.rb', line 201 def rmext_block_on_main_q(block, *args) unless block.nil? rmext_inline_or_on_main_q do block.call(*args) end end end |
#rmext_debounce_on_next_runloop(unique_id, run_immediately, &block) ⇒ Object
takes a unique_id, run_immediately bool, and block if run_immediately is true, the block is executed immediately and not counted on the next run loop, the block will be called IF it has been counted at least once. examples:
# CALLED will be printed twice. Onces immediately, and once on the next runloop: 10.times do
rmext_debounce_on_next_runloop(:my_unique_id, true) do
p "CALLED"
end
end
# CALLED will be printed once, on the next runloop: 10.times do
rmext_debounce_on_next_runloop(:my_unique_id, false) do
p "CALLED"
end
end
useful for queuing up something that should happen on the next runloop, but not every time its called. for example, reloadData. the goal was to get a similar behavior to how setNeedsDisplay/setNeedsLayout scheduled display/layout rendering on the next UI runloop pass
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
# File 'lib/motion/util.rb', line 235 def rmext_debounce_on_next_runloop(unique_id, run_immediately, &block) Thread.current["rmext_debounce_on_next_runloop"] ||= {} lookup = Thread.current["rmext_debounce_on_next_runloop"] if lookup.key?(unique_id) lookup[unique_id][0] += 1 else lookup[unique_id] = [ 0, lambda do if (debounced_times = lookup[unique_id][0]) > 0 # p "we have", debounced_times, "debounced_times queued for unique_id", unique_id block.call else # p "no debounced_times queued for unique_id", unique_id end lookup.delete(unique_id) end ] if run_immediately block.call else lookup[unique_id][0] += 1 end # p NSRunLoop.currentRunLoop, NSRunLoop.currentRunLoop.currentMode, lookup[unique_id][1] NSRunLoop.currentRunLoop.performSelector('call', target:lookup[unique_id][1], argument:nil, order:0, modes:[NSRunLoop.currentRunLoop.currentMode]) end end |
#rmext_debounce_selector_on_next_runloop(selector, run_immediately) ⇒ Object
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 |
# File 'lib/motion/util.rb', line 260 def rmext_debounce_selector_on_next_runloop(selector, run_immediately) Thread.current["rmext_debounce_selector_on_next_runloop"] ||= {} lookup = Thread.current["rmext_debounce_selector_on_next_runloop"] if lookup.key?(selector) lookup[selector] += 1 else lookup[selector] = 0 if run_immediately send(selector) else lookup[selector] += 1 end # p NSRunLoop.currentRunLoop, NSRunLoop.currentRunLoop.currentMode, self, selector, lookup[selector] block = lambda do if (debounced_times = lookup[selector]) > 0 # p "we have", debounced_times, "debounced_times queued for", self, selector send(selector) else # p "no debounced_times queued for", self, selector end lookup.delete(selector) end NSRunLoop.currentRunLoop.performSelector('call', target:block, argument:nil, order:0, modes:[NSRunLoop.currentRunLoop.currentMode]) end end |
#rmext_debounced(method_name, seconds, *args) ⇒ Object
more typical debouncing behavior
287 288 289 290 291 292 293 294 295 296 297 298 |
# File 'lib/motion/util.rb', line 287 def rmext_debounced(method_name, seconds, *args) new_method_name = "#{method_name}_#{seconds}" unless respond_to?(new_method_name) self.class.send(:define_method, new_method_name) do |*xargs| xargs.unshift(method_name) send(*xargs) end end args.unshift(new_method_name) NSObject.cancelPreviousPerformRequestsWithTarget(self, selector:"rmext_dispatch__send__", object:args) performSelector("rmext_dispatch__send__", withObject:args, afterDelay:seconds) end |
#rmext_dispatch__send__(*args) ⇒ Object
used internally by ‘rmext_debounced`
301 302 303 |
# File 'lib/motion/util.rb', line 301 def rmext_dispatch__send__(*args) send(*args) end |
#rmext_inline_or_on_main_q(&block) ⇒ Object
call the block immediately if called on the main thread, otherwise call it async on the main queue
189 190 191 192 193 194 195 |
# File 'lib/motion/util.rb', line 189 def rmext_inline_or_on_main_q(&block) if NSThread.currentThread.isMainThread block.call else rmext_on_main_q(&block) end end |
#rmext_ivar(*args) ⇒ Object
Shortcut to instance_variable_get and instance_variable_get: 1 arg for instance_variable_get 2 args for instance_variable_set
160 161 162 163 164 165 166 167 168 |
# File 'lib/motion/util.rb', line 160 def rmext_ivar(*args) if args.size == 1 instance_variable_get("@#{args[0]}") elsif args.size == 2 instance_variable_set("@#{args[0]}", args[1]) else raise "rmext_ivar called with invalid arguments: #{args.inspect}" end end |
#rmext_nil_instance_variables! ⇒ Object
170 171 172 173 174 175 176 |
# File 'lib/motion/util.rb', line 170 def rmext_nil_instance_variables! ivars = [] + instance_variables while ivar = ivars.pop instance_variable_set(ivar, nil) end true end |
#rmext_object_desc ⇒ Object
147 148 149 |
# File 'lib/motion/util.rb', line 147 def rmext_object_desc "#<#{self.className}:0x#{'%x' % (self.object_id)}(#{self.object_id})>" end |