rm-extensions 0.3.2 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/motion/util.rb +118 -0
- data/lib/rm-extensions/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4638058073ecd449cd49a4ae5d0b2c0bcea20304
|
4
|
+
data.tar.gz: fda67c1392046c93f1c7de0c6de830cf68cd733b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d78724ff4f31f6014c7dc9732cc3a6a80919f3ccc38c0abc2668f51eb21c822b2eafb3e098488a7c12acbb2d708d6b33fca5662ad253c1034d9f34474052263d
|
7
|
+
data.tar.gz: ea9fb77064f3fb6904c8ec56ab0a50fac3f61b23d41dfeeec5d7ee4051442bb869b2c7a53664d0615dbdbe3f2aae6345cea99572b9f8cd4d8de92e16a34f0086
|
data/lib/motion/util.rb
CHANGED
@@ -90,6 +90,124 @@ module RMExtensions
|
|
90
90
|
true
|
91
91
|
end
|
92
92
|
|
93
|
+
# call the block immediately if called on the main thread,
|
94
|
+
# otherwise call it async on the main queue
|
95
|
+
def rmext_inline_or_on_main_q(&block)
|
96
|
+
if NSThread.currentThread.isMainThread
|
97
|
+
block.call
|
98
|
+
else
|
99
|
+
rmext_on_main_q(&block)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# call the block immediately if called on the main thread with the given args,
|
104
|
+
# otherwise call it async on the main queue.
|
105
|
+
# silently ignores nil blocks to avoid if !block.nil? checks, useful for async callbacks
|
106
|
+
# that optionally take a callback
|
107
|
+
def rmext_block_on_main_q(block, *args)
|
108
|
+
unless block.nil?
|
109
|
+
rmext_inline_or_on_main_q do
|
110
|
+
block.call(*args)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
### EXPERIMENTAL
|
116
|
+
|
117
|
+
# takes a unique_id, run_immediately bool, and block
|
118
|
+
# if run_immediately is true, the block is executed immediately and not counted
|
119
|
+
# on the next run loop, the block will be called IF it has been counted at least once.
|
120
|
+
# examples:
|
121
|
+
#
|
122
|
+
# # CALLED will be printed twice. Onces immediately, and once on the next runloop:
|
123
|
+
# 10.times do
|
124
|
+
# rmext_debounce_on_next_runloop(:my_unique_id, true) do
|
125
|
+
# p "CALLED"
|
126
|
+
# end
|
127
|
+
# end
|
128
|
+
#
|
129
|
+
# # CALLED will be printed once, on the next runloop:
|
130
|
+
# 10.times do
|
131
|
+
# rmext_debounce_on_next_runloop(:my_unique_id, false) do
|
132
|
+
# p "CALLED"
|
133
|
+
# end
|
134
|
+
# end
|
135
|
+
#
|
136
|
+
# useful for queuing up something that should happen on the next runloop,
|
137
|
+
# but not every time its called. for example, reloadData. the goal was
|
138
|
+
# to get a similar behavior to how setNeedsDisplay/setNeedsLayout scheduled
|
139
|
+
# display/layout rendering on the next UI runloop pass
|
140
|
+
#
|
141
|
+
def rmext_debounce_on_next_runloop(unique_id, run_immediately, &block)
|
142
|
+
Thread.current["rmext_debounce_on_next_runloop"] ||= {}
|
143
|
+
lookup = Thread.current["rmext_debounce_on_next_runloop"]
|
144
|
+
if lookup.key?(unique_id)
|
145
|
+
lookup[unique_id][0] += 1
|
146
|
+
else
|
147
|
+
lookup[unique_id] = [ 0, lambda do
|
148
|
+
if (debounced_times = lookup[unique_id][0]) > 0
|
149
|
+
# p "we have", debounced_times, "debounced_times queued for unique_id", unique_id
|
150
|
+
block.call
|
151
|
+
else
|
152
|
+
# p "no debounced_times queued for unique_id", unique_id
|
153
|
+
end
|
154
|
+
lookup.delete(unique_id)
|
155
|
+
end ]
|
156
|
+
if run_immediately
|
157
|
+
block.call
|
158
|
+
else
|
159
|
+
lookup[unique_id][0] += 1
|
160
|
+
end
|
161
|
+
# p NSRunLoop.currentRunLoop, NSRunLoop.currentRunLoop.currentMode, lookup[unique_id][1]
|
162
|
+
NSRunLoop.currentRunLoop.performSelector('call', target:lookup[unique_id][1], argument:nil, order:0, modes:[NSRunLoop.currentRunLoop.currentMode])
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def rmext_debounce_selector_on_next_runloop(selector, run_immediately)
|
167
|
+
Thread.current["rmext_debounce_selector_on_next_runloop"] ||= {}
|
168
|
+
lookup = Thread.current["rmext_debounce_selector_on_next_runloop"]
|
169
|
+
if lookup.key?(selector)
|
170
|
+
lookup[selector] += 1
|
171
|
+
else
|
172
|
+
lookup[selector] = 0
|
173
|
+
if run_immediately
|
174
|
+
send(selector)
|
175
|
+
else
|
176
|
+
lookup[selector] += 1
|
177
|
+
end
|
178
|
+
# p NSRunLoop.currentRunLoop, NSRunLoop.currentRunLoop.currentMode, self, selector, lookup[selector]
|
179
|
+
block = lambda do
|
180
|
+
if (debounced_times = lookup[selector]) > 0
|
181
|
+
# p "we have", debounced_times, "debounced_times queued for", self, selector
|
182
|
+
send(selector)
|
183
|
+
else
|
184
|
+
# p "no debounced_times queued for", self, selector
|
185
|
+
end
|
186
|
+
lookup.delete(selector)
|
187
|
+
end
|
188
|
+
NSRunLoop.currentRunLoop.performSelector('call', target:block, argument:nil, order:0, modes:[NSRunLoop.currentRunLoop.currentMode])
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
# more typical debouncing behavior
|
193
|
+
def rmext_debounced(method_name, seconds, *args)
|
194
|
+
new_method_name = "#{method_name}_#{seconds}"
|
195
|
+
unless respond_to?(new_method_name)
|
196
|
+
self.class.send(:define_method, new_method_name) do |*xargs|
|
197
|
+
xargs.unshift(method_name)
|
198
|
+
send(*xargs)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
args.unshift(new_method_name)
|
202
|
+
NSObject.cancelPreviousPerformRequestsWithTarget(self, selector:"rmext_dispatch__send__", object:args)
|
203
|
+
performSelector("rmext_dispatch__send__", withObject:args, afterDelay:seconds)
|
204
|
+
end
|
205
|
+
|
206
|
+
# used internally by `rmext_debounced`
|
207
|
+
def rmext_dispatch__send__(*args)
|
208
|
+
send(*args)
|
209
|
+
end
|
210
|
+
|
93
211
|
end
|
94
212
|
|
95
213
|
end
|