|
27 | 27 | return eventName; |
28 | 28 | } |
29 | 29 |
|
30 | | -static NSNumber *RCTGetEventID(id<RCTEvent> event) |
| 30 | +static NSNumber *RCTGetEventID(NSNumber *viewTag, NSString *eventName, uint16_t coalescingKey) |
31 | 31 | { |
32 | 32 | return @( |
33 | | - ([event respondsToSelector:@selector(viewTag)] ? event.viewTag.intValue : 0) | |
34 | | - (((uint64_t)event.eventName.hash & 0xFFFF) << 32) | |
35 | | - (((uint64_t)event.coalescingKey) << 48) |
| 33 | + viewTag.intValue | |
| 34 | + (((uint64_t)eventName.hash & 0xFFFF) << 32) | |
| 35 | + (((uint64_t)coalescingKey) << 48) |
36 | 36 | ); |
37 | 37 | } |
38 | 38 |
|
| 39 | +static uint16_t RCTUniqueCoalescingKeyGenerator = 0; |
| 40 | + |
39 | 41 | @implementation RCTEventDispatcher |
40 | 42 | { |
41 | 43 | // We need this lock to protect access to _events, _eventQueue and _eventsDispatchScheduled. It's filled in on main thread and consumed on js thread. |
@@ -136,38 +138,40 @@ - (void)sendEvent:(id<RCTEvent>)event |
136 | 138 |
|
137 | 139 | [_observersLock unlock]; |
138 | 140 |
|
139 | | - if (event.canCoalesce) { |
140 | | - [_eventQueueLock lock]; |
141 | | - |
142 | | - NSNumber *eventID = RCTGetEventID(event); |
| 141 | + [_eventQueueLock lock]; |
143 | 142 |
|
| 143 | + NSNumber *eventID; |
| 144 | + if (event.canCoalesce) { |
| 145 | + eventID = RCTGetEventID(event.viewTag, event.eventName, event.coalescingKey); |
144 | 146 | id<RCTEvent> previousEvent = _events[eventID]; |
145 | 147 | if (previousEvent) { |
146 | 148 | event = [previousEvent coalesceWithEvent:event]; |
147 | 149 | } else { |
148 | 150 | [_eventQueue addObject:eventID]; |
149 | 151 | } |
150 | | - _events[eventID] = event; |
| 152 | + } else { |
| 153 | + id<RCTEvent> previousEvent = _events[eventID]; |
| 154 | + eventID = RCTGetEventID(event.viewTag, event.eventName, RCTUniqueCoalescingKeyGenerator++); |
| 155 | + RCTAssert(previousEvent == nil, @"Got event %@ which cannot be coalesced, but has the same eventID %@ as the previous event %@", event, eventID, previousEvent); |
| 156 | + [_eventQueue addObject:eventID]; |
| 157 | + } |
151 | 158 |
|
152 | | - BOOL scheduleEventsDispatch = NO; |
153 | | - if (!_eventsDispatchScheduled) { |
154 | | - _eventsDispatchScheduled = YES; |
155 | | - scheduleEventsDispatch = YES; |
156 | | - } |
| 159 | + _events[eventID] = event; |
157 | 160 |
|
158 | | - // We have to release the lock before dispatching block with events, |
159 | | - // since dispatchBlock: can be executed synchronously on the same queue. |
160 | | - // (This is happening when chrome debugging is turned on.) |
161 | | - [_eventQueueLock unlock]; |
| 161 | + BOOL scheduleEventsDispatch = NO; |
| 162 | + if (!_eventsDispatchScheduled) { |
| 163 | + _eventsDispatchScheduled = YES; |
| 164 | + scheduleEventsDispatch = YES; |
| 165 | + } |
162 | 166 |
|
163 | | - if (scheduleEventsDispatch) { |
164 | | - [_bridge dispatchBlock:^{ |
165 | | - [self flushEventsQueue]; |
166 | | - } queue:RCTJSThread]; |
167 | | - } |
168 | | - } else { |
| 167 | + // We have to release the lock before dispatching block with events, |
| 168 | + // since dispatchBlock: can be executed synchronously on the same queue. |
| 169 | + // (This is happening when chrome debugging is turned on.) |
| 170 | + [_eventQueueLock unlock]; |
| 171 | + |
| 172 | + if (scheduleEventsDispatch) { |
169 | 173 | [_bridge dispatchBlock:^{ |
170 | | - [self dispatchEvent:event]; |
| 174 | + [self flushEventsQueue]; |
171 | 175 | } queue:RCTJSThread]; |
172 | 176 | } |
173 | 177 | } |
|
0 commit comments