From 4dfe2a5a66a321f27476c205c2ba7e14a873c9b5 Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Tue, 4 Oct 2016 20:07:22 -0400 Subject: [PATCH] [ASAsyncTransaction] Make System Less Specific to Layer Display, More Readable (#2332) * Make ASAsyncTransaction system less specific to layer-display, more readable * Document weird import --- AsyncDisplayKit/ASDisplayNode.h | 2 +- .../Transactions/_ASAsyncTransaction.h | 32 +++++---- .../Transactions/_ASAsyncTransaction.mm | 71 ++++++++++++------- .../_ASAsyncTransactionContainer+Private.h | 6 +- .../_ASAsyncTransactionContainer.h | 21 +++--- .../_ASAsyncTransactionContainer.m | 42 ++++++----- .../Transactions/_ASAsyncTransactionGroup.h | 13 ++-- .../Transactions/_ASAsyncTransactionGroup.m | 22 +++--- .../Private/ASDisplayNode+UIViewBridge.mm | 10 +++ 9 files changed, 134 insertions(+), 85 deletions(-) diff --git a/AsyncDisplayKit/ASDisplayNode.h b/AsyncDisplayKit/ASDisplayNode.h index 379ea77b2f..d1adb4e1d0 100644 --- a/AsyncDisplayKit/ASDisplayNode.h +++ b/AsyncDisplayKit/ASDisplayNode.h @@ -856,7 +856,7 @@ extern NSInteger const ASDefaultDrawingPriority; * ASDisplayNode participates in ASAsyncTransactions, so you can determine when your subnodes are done rendering. * See: -(void)asyncdisplaykit_asyncTransactionContainerStateDidChange in ASDisplayNodeSubclass.h */ -@interface ASDisplayNode (ASDisplayNodeAsyncTransactionContainer) +@interface ASDisplayNode (ASAsyncTransactionContainer) @end /** UIVIew(AsyncDisplayKit) defines convenience method for adding sub-ASDisplayNode to an UIView. */ diff --git a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransaction.h b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransaction.h index 28417de27b..eb1c2063c6 100644 --- a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransaction.h +++ b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransaction.h @@ -10,14 +10,16 @@ #import +NS_ASSUME_NONNULL_BEGIN + #define ASDISPLAYNODE_DELAY_DISPLAY 0 @class _ASAsyncTransaction; typedef void(^asyncdisplaykit_async_transaction_completion_block_t)(_ASAsyncTransaction *completedTransaction, BOOL canceled); -typedef id(^asyncdisplaykit_async_transaction_operation_block_t)(void); -typedef void(^asyncdisplaykit_async_transaction_operation_completion_block_t)(id value, BOOL canceled); -typedef void(^asyncdisplaykit_async_transaction_complete_async_operation_block_t)(id value); +typedef id _Nullable(^asyncdisplaykit_async_transaction_operation_block_t)(void); +typedef void(^asyncdisplaykit_async_transaction_operation_completion_block_t)(id _Nullable value, BOOL canceled); +typedef void(^asyncdisplaykit_async_transaction_complete_async_operation_block_t)(id _Nullable value); typedef void(^asyncdisplaykit_async_transaction_async_operation_block_t)(asyncdisplaykit_async_transaction_complete_async_operation_block_t completeOperationBlock); /** @@ -54,11 +56,11 @@ extern NSInteger const ASDefaultTransactionPriority; @summary Initialize a transaction that can start collecting async operations. @see initWithCallbackQueue:commitBlock:completionBlock:executeConcurrently: - @param callbackQueue The dispatch queue that the completion blocks will be called on. - @param completionBlock A block that is called when the transaction is completed. May be NULL. + @param callbackQueue The dispatch queue that the completion blocks will be called on. Default is the main queue. + @param completionBlock A block that is called when the transaction is completed. */ -- (instancetype)initWithCallbackQueue:(dispatch_queue_t)callbackQueue - completionBlock:(asyncdisplaykit_async_transaction_completion_block_t)completionBlock; +- (instancetype)initWithCallbackQueue:(nullable dispatch_queue_t)callbackQueue + completionBlock:(nullable asyncdisplaykit_async_transaction_completion_block_t)completionBlock; /** @summary Block the main thread until the transaction is complete, including callbacks. @@ -70,18 +72,18 @@ extern NSInteger const ASDefaultTransactionPriority; /** The dispatch queue that the completion blocks will be called on. */ -@property (nonatomic, readonly, retain) dispatch_queue_t callbackQueue; +@property (nonatomic, readonly, strong) dispatch_queue_t callbackQueue; /** A block that is called when the transaction is completed. */ -@property (nonatomic, readonly, copy) asyncdisplaykit_async_transaction_completion_block_t completionBlock; +@property (nonatomic, readonly, copy, nullable) asyncdisplaykit_async_transaction_completion_block_t completionBlock; /** The state of the transaction. @see ASAsyncTransactionState */ -@property (nonatomic, readonly, assign) ASAsyncTransactionState state; +@property (readonly, assign) ASAsyncTransactionState state; /** @summary Adds a synchronous operation to the transaction. The execution block will be executed immediately. @@ -97,7 +99,7 @@ extern NSInteger const ASDefaultTransactionPriority; */ - (void)addOperationWithBlock:(asyncdisplaykit_async_transaction_operation_block_t)block queue:(dispatch_queue_t)queue - completion:(asyncdisplaykit_async_transaction_operation_completion_block_t)completion; + completion:(nullable asyncdisplaykit_async_transaction_operation_completion_block_t)completion; /** @summary Adds a synchronous operation to the transaction. The execution block will be executed immediately. @@ -115,7 +117,7 @@ extern NSInteger const ASDefaultTransactionPriority; - (void)addOperationWithBlock:(asyncdisplaykit_async_transaction_operation_block_t)block priority:(NSInteger)priority queue:(dispatch_queue_t)queue - completion:(asyncdisplaykit_async_transaction_operation_completion_block_t)completion; + completion:(nullable asyncdisplaykit_async_transaction_operation_completion_block_t)completion; /** @@ -134,7 +136,7 @@ extern NSInteger const ASDefaultTransactionPriority; */ - (void)addAsyncOperationWithBlock:(asyncdisplaykit_async_transaction_async_operation_block_t)block queue:(dispatch_queue_t)queue - completion:(asyncdisplaykit_async_transaction_operation_completion_block_t)completion; + completion:(nullable asyncdisplaykit_async_transaction_operation_completion_block_t)completion; /** @summary Adds an async operation to the transaction. The execution block will be executed immediately. @@ -154,7 +156,7 @@ extern NSInteger const ASDefaultTransactionPriority; - (void)addAsyncOperationWithBlock:(asyncdisplaykit_async_transaction_async_operation_block_t)block priority:(NSInteger)priority queue:(dispatch_queue_t)queue - completion:(asyncdisplaykit_async_transaction_operation_completion_block_t)completion; + completion:(nullable asyncdisplaykit_async_transaction_operation_completion_block_t)completion; @@ -189,3 +191,5 @@ extern NSInteger const ASDefaultTransactionPriority; - (void)commit; @end + +NS_ASSUME_NONNULL_END diff --git a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransaction.mm b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransaction.mm index ccb9f00a09..59df1fd14c 100644 --- a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransaction.mm +++ b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransaction.mm @@ -8,24 +8,28 @@ // of patent rights can be found in the PATENTS file in the same directory. // +// We need this import for UITrackingRunLoopMode +#import + #import "_ASAsyncTransaction.h" #import "_ASAsyncTransactionGroup.h" #import #import #import +#import #define ASAsyncTransactionAssertMainThread() NSAssert(0 != pthread_main_np(), @"This method must be called on the main thread"); NSInteger const ASDefaultTransactionPriority = 0; -@interface ASDisplayNodeAsyncTransactionOperation : NSObject +@interface ASAsyncTransactionOperation : NSObject - (instancetype)initWithOperationCompletionBlock:(asyncdisplaykit_async_transaction_operation_completion_block_t)operationCompletionBlock; @property (nonatomic, copy) asyncdisplaykit_async_transaction_operation_completion_block_t operationCompletionBlock; @property (nonatomic, strong) id value; // set on bg queue by the operation block @end -@implementation ASDisplayNodeAsyncTransactionOperation +@implementation ASAsyncTransactionOperation - (instancetype)initWithOperationCompletionBlock:(asyncdisplaykit_async_transaction_operation_completion_block_t)operationCompletionBlock { @@ -51,7 +55,7 @@ NSInteger const ASDefaultTransactionPriority = 0; - (NSString *)description { - return [NSString stringWithFormat:@" *_operations; + _Atomic(ASAsyncTransactionState) _state; } #pragma mark - @@ -333,7 +338,7 @@ ASAsyncTransactionQueue & ASAsyncTransactionQueue::instance() _callbackQueue = callbackQueue; _completionBlock = [completionBlock copy]; - __atomic_store_n(&_state, ASAsyncTransactionStateOpen, __ATOMIC_SEQ_CST); + _state = ATOMIC_VAR_INIT(ASAsyncTransactionStateOpen); } return self; } @@ -341,14 +346,25 @@ ASAsyncTransactionQueue & ASAsyncTransactionQueue::instance() - (void)dealloc { // Uncommitted transactions break our guarantees about releasing completion blocks on callbackQueue. - NSAssert(__atomic_load_n(&_state, __ATOMIC_SEQ_CST) != ASAsyncTransactionStateOpen, @"Uncommitted ASAsyncTransactions are not allowed"); + NSAssert(self.state != ASAsyncTransactionStateOpen, @"Uncommitted ASAsyncTransactions are not allowed"); if (_group) { _group->release(); } } -#pragma mark - -#pragma mark Transaction Management +#pragma mark - Properties + +- (ASAsyncTransactionState)state +{ + return atomic_load(&_state); +} + +- (void)setState:(ASAsyncTransactionState)state +{ + atomic_store(&_state, state); +} + +#pragma mark - Transaction Management - (void)addAsyncOperationWithBlock:(asyncdisplaykit_async_transaction_async_operation_block_t)block queue:(dispatch_queue_t)queue @@ -366,15 +382,15 @@ ASAsyncTransactionQueue & ASAsyncTransactionQueue::instance() completion:(asyncdisplaykit_async_transaction_operation_completion_block_t)completion { ASAsyncTransactionAssertMainThread(); - NSAssert(__atomic_load_n(&_state, __ATOMIC_SEQ_CST) == ASAsyncTransactionStateOpen, @"You can only add operations to open transactions"); + NSAssert(self.state == ASAsyncTransactionStateOpen, @"You can only add operations to open transactions"); [self _ensureTransactionData]; - ASDisplayNodeAsyncTransactionOperation *operation = [[ASDisplayNodeAsyncTransactionOperation alloc] initWithOperationCompletionBlock:completion]; + ASAsyncTransactionOperation *operation = [[ASAsyncTransactionOperation alloc] initWithOperationCompletionBlock:completion]; [_operations addObject:operation]; _group->schedule(priority, queue, ^{ @autoreleasepool { - if (__atomic_load_n(&_state, __ATOMIC_SEQ_CST) != ASAsyncTransactionStateCanceled) { + if (self.state != ASAsyncTransactionStateCanceled) { _group->enter(); block(^(id value){ operation.value = value; @@ -401,15 +417,15 @@ ASAsyncTransactionQueue & ASAsyncTransactionQueue::instance() completion:(asyncdisplaykit_async_transaction_operation_completion_block_t)completion { ASAsyncTransactionAssertMainThread(); - NSAssert(__atomic_load_n(&_state, __ATOMIC_SEQ_CST) == ASAsyncTransactionStateOpen, @"You can only add operations to open transactions"); + NSAssert(self.state == ASAsyncTransactionStateOpen, @"You can only add operations to open transactions"); [self _ensureTransactionData]; - ASDisplayNodeAsyncTransactionOperation *operation = [[ASDisplayNodeAsyncTransactionOperation alloc] initWithOperationCompletionBlock:completion]; + ASAsyncTransactionOperation *operation = [[ASAsyncTransactionOperation alloc] initWithOperationCompletionBlock:completion]; [_operations addObject:operation]; _group->schedule(priority, queue, ^{ @autoreleasepool { - if (__atomic_load_n(&_state, __ATOMIC_SEQ_CST) != ASAsyncTransactionStateCanceled) { + if (self.state != ASAsyncTransactionStateCanceled) { operation.value = block(); } } @@ -428,15 +444,15 @@ ASAsyncTransactionQueue & ASAsyncTransactionQueue::instance() - (void)cancel { ASAsyncTransactionAssertMainThread(); - NSAssert(__atomic_load_n(&_state, __ATOMIC_SEQ_CST) != ASAsyncTransactionStateOpen, @"You can only cancel a committed or already-canceled transaction"); - __atomic_store_n(&_state, ASAsyncTransactionStateCanceled, __ATOMIC_SEQ_CST); + NSAssert(self.state != ASAsyncTransactionStateOpen, @"You can only cancel a committed or already-canceled transaction"); + self.state = ASAsyncTransactionStateCanceled; } - (void)commit { ASAsyncTransactionAssertMainThread(); - NSAssert(__atomic_load_n(&_state, __ATOMIC_SEQ_CST) == ASAsyncTransactionStateOpen, @"You cannot double-commit a transaction"); - __atomic_store_n(&_state, ASAsyncTransactionStateCommitted, __ATOMIC_SEQ_CST); + NSAssert(self.state == ASAsyncTransactionStateOpen, @"You cannot double-commit a transaction"); + self.state = ASAsyncTransactionStateCommitted; if ([_operations count] == 0) { // Fast path: if a transaction was opened, but no operations were added, execute completion block synchronously. @@ -457,16 +473,17 @@ ASAsyncTransactionQueue & ASAsyncTransactionQueue::instance() - (void)completeTransaction { - if (__atomic_load_n(&_state, __ATOMIC_SEQ_CST) != ASAsyncTransactionStateComplete) { - BOOL isCanceled = (__atomic_load_n(&_state, __ATOMIC_SEQ_CST) == ASAsyncTransactionStateCanceled); - for (ASDisplayNodeAsyncTransactionOperation *operation in _operations) { + ASAsyncTransactionState state = self.state; + if (state != ASAsyncTransactionStateComplete) { + BOOL isCanceled = (state == ASAsyncTransactionStateCanceled); + for (ASAsyncTransactionOperation *operation in _operations) { [operation callAndReleaseCompletionBlock:isCanceled]; } - // Always set _state to Complete, even if we were cancelled, to block any extraneous + // Always set state to Complete, even if we were cancelled, to block any extraneous // calls to this method that may have been scheduled for the next runloop // (e.g. if we needed to force one in this runloop with -waitUntilComplete, but another was already scheduled) - __atomic_store_n(&_state, ASAsyncTransactionStateComplete, __ATOMIC_SEQ_CST); + self.state = ASAsyncTransactionStateComplete; if (_completionBlock) { _completionBlock(self, isCanceled); @@ -477,7 +494,7 @@ ASAsyncTransactionQueue & ASAsyncTransactionQueue::instance() - (void)waitUntilComplete { ASAsyncTransactionAssertMainThread(); - if (__atomic_load_n(&_state, __ATOMIC_SEQ_CST) != ASAsyncTransactionStateComplete) { + if (self.state != ASAsyncTransactionStateComplete) { if (_group) { NSAssert(_callbackQueue == dispatch_get_main_queue(), nil); _group->wait(); @@ -487,9 +504,9 @@ ASAsyncTransactionQueue & ASAsyncTransactionQueue::instance() // commit ourselves via the group to avoid double-committing the transaction. // This is only necessary when forcing display work to complete before allowing the runloop // to continue, e.g. in the implementation of -[ASDisplayNode recursivelyEnsureDisplay]. - if (__atomic_load_n(&_state, __ATOMIC_SEQ_CST) == ASAsyncTransactionStateOpen) { + if (self.state == ASAsyncTransactionStateOpen) { [_ASAsyncTransactionGroup commit]; - NSAssert(__atomic_load_n(&_state, __ATOMIC_SEQ_CST) != ASAsyncTransactionStateOpen, @"Transaction should not be open after committing group"); + NSAssert(self.state != ASAsyncTransactionStateOpen, @"Transaction should not be open after committing group"); } // If we needed to commit the group above, -completeTransaction may have already been run. // It is designed to accommodate this by checking _state to ensure it is not complete. @@ -514,7 +531,7 @@ ASAsyncTransactionQueue & ASAsyncTransactionQueue::instance() - (NSString *)description { - return [NSString stringWithFormat:@"<_ASAsyncTransaction: %p - _state = %lu, _group = %p, _operations = %@>", self, (unsigned long)__atomic_load_n(&_state, __ATOMIC_SEQ_CST), _group, _operations]; + return [NSString stringWithFormat:@"<_ASAsyncTransaction: %p - _state = %lu, _group = %p, _operations = %@>", self, (unsigned long)self.state, _group, _operations]; } @end diff --git a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionContainer+Private.h b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionContainer+Private.h index ad0eb377c9..579362baca 100644 --- a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionContainer+Private.h +++ b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionContainer+Private.h @@ -10,11 +10,13 @@ #import +NS_ASSUME_NONNULL_BEGIN @interface CALayer (ASAsyncTransactionContainerTransactions) -@property (nonatomic, strong, setter=asyncdisplaykit_setAsyncLayerTransactions:) NSHashTable *asyncdisplaykit_asyncLayerTransactions; -@property (nonatomic, strong, setter=asyncdisplaykit_setCurrentAsyncLayerTransaction:) _ASAsyncTransaction *asyncdisplaykit_currentAsyncLayerTransaction; +@property (nonatomic, strong, nullable, setter=asyncdisplaykit_setAsyncLayerTransactions:) NSHashTable<_ASAsyncTransaction *> *asyncdisplaykit_asyncLayerTransactions; - (void)asyncdisplaykit_asyncTransactionContainerWillBeginTransaction:(_ASAsyncTransaction *)transaction; - (void)asyncdisplaykit_asyncTransactionContainerDidCompleteTransaction:(_ASAsyncTransaction *)transaction; @end + +NS_ASSUME_NONNULL_END diff --git a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionContainer.h b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionContainer.h index 399a637a87..cb83c2920e 100644 --- a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionContainer.h +++ b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionContainer.h @@ -10,6 +10,7 @@ #import +NS_ASSUME_NONNULL_BEGIN @class _ASAsyncTransaction; @@ -26,11 +27,11 @@ typedef NS_ENUM(NSUInteger, ASAsyncTransactionContainerState) { ASAsyncTransactionContainerStatePendingTransactions, }; -@protocol ASDisplayNodeAsyncTransactionContainer +@protocol ASAsyncTransactionContainer /** - @summary If YES, the receiver is marked as a container for async display, grouping all of the async display calls - in the layer hierarchy below the receiver together in a single ASAsyncTransaction. + @summary If YES, the receiver is marked as a container for async transactions, grouping all of the transactions + in the container hierarchy below the receiver together in a single ASAsyncTransaction. @default NO */ @@ -46,22 +47,26 @@ typedef NS_ENUM(NSUInteger, ASAsyncTransactionContainerState) { */ - (void)asyncdisplaykit_cancelAsyncTransactions; +@property (nonatomic, strong, nullable, setter=asyncdisplaykit_setCurrentAsyncTransaction:) _ASAsyncTransaction *asyncdisplaykit_currentAsyncTransaction; + @end -@interface CALayer (ASDisplayNodeAsyncTransactionContainer) +@interface CALayer (ASAsyncTransactionContainer) /** - @summary Returns the current async transaction for this container layer. A new transaction is created if one + @summary Returns the current async transaction for this layer. A new transaction is created if one did not already exist. This method will always return an open, uncommitted transaction. @desc asyncdisplaykit_isAsyncTransactionContainer does not need to be YES for this to return a transaction. */ -@property (nonatomic, readonly, strong) _ASAsyncTransaction *asyncdisplaykit_asyncTransaction; +@property (nonatomic, readonly, strong, nullable) _ASAsyncTransaction *asyncdisplaykit_asyncTransaction; /** @summary Goes up the superlayer chain until it finds the first layer with asyncdisplaykit_isAsyncTransactionContainer=YES (including the receiver) and returns it. Returns nil if no parent container is found. */ -@property (nonatomic, readonly, strong) CALayer *asyncdisplaykit_parentTransactionContainer; +@property (nonatomic, readonly, strong, nullable) CALayer *asyncdisplaykit_parentTransactionContainer; @end -@interface UIView (ASDisplayNodeAsyncTransactionContainer) +@interface UIView (ASAsyncTransactionContainer) @end + +NS_ASSUME_NONNULL_END diff --git a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionContainer.m b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionContainer.m index c4f7a2da66..560bf7bb4c 100644 --- a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionContainer.m +++ b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionContainer.m @@ -19,16 +19,6 @@ static const char *ASDisplayNodeAssociatedCurrentTransactionKey = "ASAssociatedC @implementation CALayer (ASAsyncTransactionContainerTransactions) -- (_ASAsyncTransaction *)asyncdisplaykit_currentAsyncLayerTransaction -{ - return objc_getAssociatedObject(self, ASDisplayNodeAssociatedCurrentTransactionKey); -} - -- (void)asyncdisplaykit_setCurrentAsyncLayerTransaction:(_ASAsyncTransaction *)transaction -{ - objc_setAssociatedObject(self, ASDisplayNodeAssociatedCurrentTransactionKey, transaction, OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - - (NSHashTable *)asyncdisplaykit_asyncLayerTransactions { return objc_getAssociatedObject(self, ASDisplayNodeAssociatedTransactionsKey); @@ -46,7 +36,17 @@ static const char *ASDisplayNodeAssociatedCurrentTransactionKey = "ASAssociatedC static const char *ASAsyncTransactionIsContainerKey = "ASTransactionIsContainer"; -@implementation CALayer (ASDisplayNodeAsyncTransactionContainer) +@implementation CALayer (ASAsyncTransactionContainer) + +- (_ASAsyncTransaction *)asyncdisplaykit_currentAsyncTransaction +{ + return objc_getAssociatedObject(self, ASDisplayNodeAssociatedCurrentTransactionKey); +} + +- (void)asyncdisplaykit_setCurrentAsyncTransaction:(_ASAsyncTransaction *)transaction +{ + objc_setAssociatedObject(self, ASDisplayNodeAssociatedCurrentTransactionKey, transaction, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} - (BOOL)asyncdisplaykit_isAsyncTransactionContainer { @@ -70,9 +70,9 @@ static const char *ASAsyncTransactionIsContainerKey = "ASTransactionIsContainer" // If there was an open transaction, commit and clear the current transaction. Otherwise: // (1) The run loop observer will try to commit a canceled transaction which is not allowed // (2) We leave the canceled transaction attached to the layer, dooming future operations - _ASAsyncTransaction *currentTransaction = self.asyncdisplaykit_currentAsyncLayerTransaction; + _ASAsyncTransaction *currentTransaction = self.asyncdisplaykit_currentAsyncTransaction; [currentTransaction commit]; - self.asyncdisplaykit_currentAsyncLayerTransaction = nil; + self.asyncdisplaykit_currentAsyncTransaction = nil; for (_ASAsyncTransaction *transaction in [self.asyncdisplaykit_asyncLayerTransactions copy]) { [transaction cancel]; @@ -81,7 +81,7 @@ static const char *ASAsyncTransactionIsContainerKey = "ASTransactionIsContainer" - (_ASAsyncTransaction *)asyncdisplaykit_asyncTransaction { - _ASAsyncTransaction *transaction = self.asyncdisplaykit_currentAsyncLayerTransaction; + _ASAsyncTransaction *transaction = self.asyncdisplaykit_currentAsyncTransaction; if (transaction == nil) { NSHashTable *transactions = self.asyncdisplaykit_asyncLayerTransactions; if (transactions == nil) { @@ -98,7 +98,7 @@ static const char *ASAsyncTransactionIsContainerKey = "ASTransactionIsContainer" [self asyncdisplaykit_asyncTransactionContainerDidCompleteTransaction:completedTransaction]; }]; [transactions addObject:transaction]; - self.asyncdisplaykit_currentAsyncLayerTransaction = transaction; + self.asyncdisplaykit_currentAsyncTransaction = transaction; [self asyncdisplaykit_asyncTransactionContainerWillBeginTransaction:transaction]; } [[_ASAsyncTransactionGroup mainTransactionGroup] addTransactionContainer:self]; @@ -116,7 +116,7 @@ static const char *ASAsyncTransactionIsContainerKey = "ASTransactionIsContainer" @end -@implementation UIView (ASDisplayNodeAsyncTransactionContainer) +@implementation UIView (ASAsyncTransactionContainer) - (BOOL)asyncdisplaykit_isAsyncTransactionContainer { @@ -143,4 +143,14 @@ static const char *ASAsyncTransactionIsContainerKey = "ASTransactionIsContainer" // No-op in the base class. } +- (void)asyncdisplaykit_setCurrentAsyncTransaction:(_ASAsyncTransaction *)transaction +{ + self.layer.asyncdisplaykit_currentAsyncTransaction = transaction; +} + +- (_ASAsyncTransaction *)asyncdisplaykit_currentAsyncTransaction +{ + return self.layer.asyncdisplaykit_currentAsyncTransaction; +} + @end diff --git a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionGroup.h b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionGroup.h index ac816b2938..b77b8241b3 100644 --- a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionGroup.h +++ b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionGroup.h @@ -8,19 +8,20 @@ // of patent rights can be found in the PATENTS file in the same directory. // -#import - +NS_ASSUME_NONNULL_BEGIN @class _ASAsyncTransaction; +@protocol ASAsyncTransactionContainer; -/// A group of transaction container layers, for which the current transactions are committed together at the end of the next runloop tick. +/// A group of transaction containers, for which the current transactions are committed together at the end of the next runloop tick. @interface _ASAsyncTransactionGroup : NSObject /// The main transaction group is scheduled to commit on every tick of the main runloop. -+ (instancetype)mainTransactionGroup; ++ (_ASAsyncTransactionGroup *)mainTransactionGroup; + (void)commit; /// Add a transaction container to be committed. -/// @param containerLayer A layer containing a transaction to be committed. May or may not be a container layer. /// @see ASAsyncTransactionContainer -- (void)addTransactionContainer:(CALayer *)containerLayer; +- (void)addTransactionContainer:(id)container; @end + +NS_ASSUME_NONNULL_END diff --git a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionGroup.m b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionGroup.m index d9827a139d..9f226c3619 100644 --- a/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionGroup.m +++ b/AsyncDisplayKit/Details/Transactions/_ASAsyncTransactionGroup.m @@ -22,7 +22,7 @@ static void _transactionGroupRunLoopObserverCallback(CFRunLoopObserverRef observ @end @implementation _ASAsyncTransactionGroup { - NSHashTable *_containerLayers; + NSHashTable> *_containers; } + (_ASAsyncTransactionGroup *)mainTransactionGroup @@ -67,31 +67,31 @@ static void _transactionGroupRunLoopObserverCallback(CFRunLoopObserverRef observ - (instancetype)init { if ((self = [super init])) { - _containerLayers = [NSHashTable hashTableWithOptions:NSPointerFunctionsObjectPointerPersonality]; + _containers = [NSHashTable hashTableWithOptions:NSHashTableObjectPointerPersonality]; } return self; } -- (void)addTransactionContainer:(CALayer *)containerLayer +- (void)addTransactionContainer:(id)container { ASDisplayNodeAssertMainThread(); - ASDisplayNodeAssert(containerLayer != nil, @"No container"); - [_containerLayers addObject:containerLayer]; + ASDisplayNodeAssert(container != nil, @"No container"); + [_containers addObject:container]; } - (void)commit { ASDisplayNodeAssertMainThread(); - if ([_containerLayers count]) { - NSHashTable *containerLayersToCommit = _containerLayers; - _containerLayers = [NSHashTable hashTableWithOptions:NSPointerFunctionsObjectPointerPersonality]; + if ([_containers count]) { + NSHashTable *containersToCommit = _containers; + _containers = [NSHashTable hashTableWithOptions:NSHashTableObjectPointerPersonality]; - for (CALayer *containerLayer in containerLayersToCommit) { + for (id container in containersToCommit) { // Note that the act of committing a transaction may open a new transaction, // so we must nil out the transaction we're committing first. - _ASAsyncTransaction *transaction = containerLayer.asyncdisplaykit_currentAsyncLayerTransaction; - containerLayer.asyncdisplaykit_currentAsyncLayerTransaction = nil; + _ASAsyncTransaction *transaction = container.asyncdisplaykit_currentAsyncTransaction; + container.asyncdisplaykit_currentAsyncTransaction = nil; [transaction commit]; } } diff --git a/AsyncDisplayKit/Private/ASDisplayNode+UIViewBridge.mm b/AsyncDisplayKit/Private/ASDisplayNode+UIViewBridge.mm index 39ee0f9fa3..f4e67b7f9a 100644 --- a/AsyncDisplayKit/Private/ASDisplayNode+UIViewBridge.mm +++ b/AsyncDisplayKit/Private/ASDisplayNode+UIViewBridge.mm @@ -974,4 +974,14 @@ nodeProperty = nodeValueExpr; _setToViewOnly(viewAndPendingViewStateProperty, vi [_layer asyncdisplaykit_cancelAsyncTransactions]; } +- (void)asyncdisplaykit_setCurrentAsyncTransaction:(_ASAsyncTransaction *)transaction +{ + _layer.asyncdisplaykit_currentAsyncTransaction = transaction; +} + +- (_ASAsyncTransaction *)asyncdisplaykit_currentAsyncTransaction +{ + return _layer.asyncdisplaykit_currentAsyncTransaction; +} + @end