mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-15 18:59:54 +00:00
[ASAsyncTransaction] Make System Less Specific to Layer Display, More Readable (#2332)
* Make ASAsyncTransaction system less specific to layer-display, more readable * Document weird import
This commit is contained in:
parent
2de129008f
commit
4dfe2a5a66
@ -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) <ASDisplayNodeAsyncTransactionContainer>
|
||||
@interface ASDisplayNode (ASAsyncTransactionContainer) <ASAsyncTransactionContainer>
|
||||
@end
|
||||
|
||||
/** UIVIew(AsyncDisplayKit) defines convenience method for adding sub-ASDisplayNode to an UIView. */
|
||||
|
||||
@ -10,14 +10,16 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
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<NSObject>(^asyncdisplaykit_async_transaction_operation_block_t)(void);
|
||||
typedef void(^asyncdisplaykit_async_transaction_operation_completion_block_t)(id<NSObject> value, BOOL canceled);
|
||||
typedef void(^asyncdisplaykit_async_transaction_complete_async_operation_block_t)(id<NSObject> value);
|
||||
typedef id<NSObject> _Nullable(^asyncdisplaykit_async_transaction_operation_block_t)(void);
|
||||
typedef void(^asyncdisplaykit_async_transaction_operation_completion_block_t)(id<NSObject> _Nullable value, BOOL canceled);
|
||||
typedef void(^asyncdisplaykit_async_transaction_complete_async_operation_block_t)(id<NSObject> _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
|
||||
|
||||
@ -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 <UIKit/UIApplication.h>
|
||||
|
||||
#import "_ASAsyncTransaction.h"
|
||||
#import "_ASAsyncTransactionGroup.h"
|
||||
|
||||
#import <list>
|
||||
#import <map>
|
||||
#import <mutex>
|
||||
#import <stdatomic.h>
|
||||
|
||||
#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<NSObject> 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:@"<ASDisplayNodeAsyncTransactionOperation: %p - value = %@", self, self.value];
|
||||
return [NSString stringWithFormat:@"<ASAsyncTransactionOperation: %p - value = %@", self, self.value];
|
||||
}
|
||||
|
||||
@end
|
||||
@ -317,7 +321,8 @@ ASAsyncTransactionQueue & ASAsyncTransactionQueue::instance()
|
||||
@implementation _ASAsyncTransaction
|
||||
{
|
||||
ASAsyncTransactionQueue::Group *_group;
|
||||
NSMutableArray *_operations;
|
||||
NSMutableArray<ASAsyncTransactionOperation *> *_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<NSObject> 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
|
||||
|
||||
@ -10,11 +10,13 @@
|
||||
|
||||
#import <AsyncDisplayKit/_ASAsyncTransactionContainer.h>
|
||||
|
||||
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
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
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) <ASDisplayNodeAsyncTransactionContainer>
|
||||
@interface CALayer (ASAsyncTransactionContainer) <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) <ASDisplayNodeAsyncTransactionContainer>
|
||||
@interface UIView (ASAsyncTransactionContainer) <ASAsyncTransactionContainer>
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -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
|
||||
|
||||
@ -8,19 +8,20 @@
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
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<ASAsyncTransactionContainer>)container;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -22,7 +22,7 @@ static void _transactionGroupRunLoopObserverCallback(CFRunLoopObserverRef observ
|
||||
@end
|
||||
|
||||
@implementation _ASAsyncTransactionGroup {
|
||||
NSHashTable *_containerLayers;
|
||||
NSHashTable<id<ASAsyncTransactionContainer>> *_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<ASAsyncTransactionContainer>)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<ASAsyncTransactionContainer> 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];
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user