Add timestamp to notifications of rendering engine and avoid race conditions in ASRangeControllerBeta

- Accurately remove notification observer
This commit is contained in:
Huy Nguyen 2016-02-04 13:59:43 -08:00
parent 3c135788cb
commit fda9efafa6
3 changed files with 22 additions and 9 deletions

View File

@ -30,6 +30,7 @@
NSInteger const ASDefaultDrawingPriority = ASDefaultTransactionPriority; NSInteger const ASDefaultDrawingPriority = ASDefaultTransactionPriority;
NSString * const ASRenderingEngineDidDisplayScheduledNodesNotification = @"ASRenderingEngineDidDisplayScheduledNodes"; NSString * const ASRenderingEngineDidDisplayScheduledNodesNotification = @"ASRenderingEngineDidDisplayScheduledNodes";
NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp = @"ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp";
@interface _ASDisplayNodePosition : NSObject @interface _ASDisplayNodePosition : NSObject
@ -276,12 +277,14 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
ASDN::MutexLocker l(displaySchedulerLock); ASDN::MutexLocker l(displaySchedulerLock);
displayScheduled = NO; displayScheduled = NO;
NSSet *displayingNodes = [nodesToDisplay copy]; NSSet *displayingNodes = [nodesToDisplay copy];
CFAbsoluteTime timestamp = CFAbsoluteTimeGetCurrent();
nodesToDisplay = nil; nodesToDisplay = nil;
for (ASDisplayNode *node in displayingNodes) { for (ASDisplayNode *node in displayingNodes) {
[node __recursivelyTriggerDisplayAndBlock:NO]; [node __recursivelyTriggerDisplayAndBlock:NO];
} }
[[NSNotificationCenter defaultCenter] postNotificationName:ASRenderingEngineDidDisplayScheduledNodesNotification [[NSNotificationCenter defaultCenter] postNotificationName:ASRenderingEngineDidDisplayScheduledNodesNotification
object:nil]; object:displayingNodes
userInfo:@{ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp: [NSNumber numberWithDouble:timestamp]}];
}); });
} }
} }

View File

@ -27,6 +27,7 @@
NSSet<NSIndexPath *> *_allPreviousIndexPaths; NSSet<NSIndexPath *> *_allPreviousIndexPaths;
ASLayoutRangeMode _currentRangeMode; ASLayoutRangeMode _currentRangeMode;
BOOL _didRegisterForNotifications; BOOL _didRegisterForNotifications;
CFAbsoluteTime _pendingDisplayNodesTimestamp;
} }
@end @end
@ -48,7 +49,7 @@
- (void)dealloc - (void)dealloc
{ {
if (_didRegisterForNotifications) { if (_didRegisterForNotifications) {
[[NSNotificationCenter defaultCenter] removeObserver:self]; [[NSNotificationCenter defaultCenter] removeObserver:self name:ASRenderingEngineDidDisplayScheduledNodesNotification object:nil];
} }
} }
@ -244,6 +245,10 @@
} }
} }
if (_didRegisterForNotifications) {
_pendingDisplayNodesTimestamp = CFAbsoluteTimeGetCurrent();
}
_rangeIsValid = YES; _rangeIsValid = YES;
_queuedRangeUpdate = NO; _queuedRangeUpdate = NO;
@ -280,7 +285,7 @@
currentRangeMode:_currentRangeMode]; currentRangeMode:_currentRangeMode];
if (_currentRangeMode != nextRangeMode) { if (_currentRangeMode != nextRangeMode) {
[[NSNotificationCenter defaultCenter] addObserver:self [[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(scheduledNodesDidDisplay) selector:@selector(scheduledNodesDidDisplay:)
name:ASRenderingEngineDidDisplayScheduledNodesNotification name:ASRenderingEngineDidDisplayScheduledNodesNotification
object:nil]; object:nil];
_didRegisterForNotifications = YES; _didRegisterForNotifications = YES;
@ -288,12 +293,16 @@
} }
} }
- (void)scheduledNodesDidDisplay - (void)scheduledNodesDidDisplay:(NSNotification *)notification
{ {
[[NSNotificationCenter defaultCenter] removeObserver:self]; CFAbsoluteTime notificationTimestamp = ((NSNumber *)[notification.userInfo objectForKey:ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp]).doubleValue;
if (_pendingDisplayNodesTimestamp < notificationTimestamp) {
// The rendering engine has processed all the nodes this range controller scheduled. Let's schedule a range update
[[NSNotificationCenter defaultCenter] removeObserver:self name:ASRenderingEngineDidDisplayScheduledNodesNotification object:nil];
_didRegisterForNotifications = NO; _didRegisterForNotifications = NO;
[self scheduleRangeUpdate]; [self scheduleRangeUpdate];
}
} }
#pragma mark - Cell node view handling #pragma mark - Cell node view handling

View File

@ -38,6 +38,7 @@ typedef NS_OPTIONS(NSUInteger, ASDisplayNodeMethodOverrides)
@class _ASDisplayNodePosition; @class _ASDisplayNodePosition;
FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayScheduledNodesNotification; FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayScheduledNodesNotification;
FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp;
// Allow 2^n increments of begin disabling hierarchy notifications // Allow 2^n increments of begin disabling hierarchy notifications
#define VISIBILITY_NOTIFICATIONS_DISABLED_BITS 4 #define VISIBILITY_NOTIFICATIONS_DISABLED_BITS 4