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
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.
59 60 61 |
# File 'lib/motion/util.rb', line 59 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
84 85 86 87 88 89 90 91 |
# File 'lib/motion/util.rb', line 84 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
107 108 109 110 111 112 113 |
# File 'lib/motion/util.rb', line 107 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
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/motion/util.rb', line 141 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
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/motion/util.rb', line 166 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
193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/motion/util.rb', line 193 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`
207 208 209 |
# File 'lib/motion/util.rb', line 207 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
95 96 97 98 99 100 101 |
# File 'lib/motion/util.rb', line 95 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
66 67 68 69 70 71 72 73 74 |
# File 'lib/motion/util.rb', line 66 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
76 77 78 79 80 81 82 |
# File 'lib/motion/util.rb', line 76 def rmext_nil_instance_variables! ivars = [] + instance_variables while ivar = ivars.pop instance_variable_set(ivar, nil) end true end |