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.
81 82 83 |
# File 'lib/motion/util.rb', line 81 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
106 107 108 109 110 111 112 113 |
# File 'lib/motion/util.rb', line 106 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
129 130 131 132 133 134 135 |
# File 'lib/motion/util.rb', line 129 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
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/motion/util.rb', line 163 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
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
# File 'lib/motion/util.rb', line 188 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
215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/motion/util.rb', line 215 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`
229 230 231 |
# File 'lib/motion/util.rb', line 229 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
117 118 119 120 121 122 123 |
# File 'lib/motion/util.rb', line 117 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
88 89 90 91 92 93 94 95 96 |
# File 'lib/motion/util.rb', line 88 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
98 99 100 101 102 103 104 |
# File 'lib/motion/util.rb', line 98 def rmext_nil_instance_variables! ivars = [] + instance_variables while ivar = ivars.pop instance_variable_set(ivar, nil) end true end |
#rmext_object_desc ⇒ Object
75 76 77 |
# File 'lib/motion/util.rb', line 75 def rmext_object_desc "#<#{self.className}:0x#{'%x' % (self.object_id)}(#{self.object_id})>" end |