mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-22 13:34:44 +00:00
178 lines
5.8 KiB
Objective-C
178 lines
5.8 KiB
Objective-C
/* Copyright (c) 2014-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*/
|
|
|
|
#import "_ASAsyncTransaction.h"
|
|
|
|
#import "ASAssert.h"
|
|
|
|
@interface ASDisplayNodeAsyncTransactionOperation : NSObject
|
|
- (id)initWithOperationCompletionBlock:(asyncdisplaykit_async_transaction_operation_completion_block_t)operationCompletionBlock;
|
|
@property (nonatomic, copy) asyncdisplaykit_async_transaction_operation_completion_block_t operationCompletionBlock;
|
|
@property (atomic, retain) id<NSObject> value; // set on bg queue by the operation block
|
|
@end
|
|
|
|
@implementation ASDisplayNodeAsyncTransactionOperation
|
|
|
|
- (id)initWithOperationCompletionBlock:(asyncdisplaykit_async_transaction_operation_completion_block_t)operationCompletionBlock
|
|
{
|
|
if ((self = [super init])) {
|
|
_operationCompletionBlock = [operationCompletionBlock copy];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
ASDisplayNodeAssertNil(_operationCompletionBlock, @"Should have been called and released before -dealloc");
|
|
}
|
|
|
|
- (void)callAndReleaseCompletionBlock:(BOOL)canceled;
|
|
{
|
|
if (_operationCompletionBlock) {
|
|
_operationCompletionBlock(self.value, canceled);
|
|
// Guarantee that _operationCompletionBlock is released on _callbackQueue:
|
|
self.operationCompletionBlock = nil;
|
|
}
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation _ASAsyncTransaction
|
|
{
|
|
dispatch_group_t _group;
|
|
NSMutableArray *_operations;
|
|
}
|
|
|
|
#pragma mark -
|
|
#pragma mark Lifecycle
|
|
|
|
- (id)initWithCallbackQueue:(dispatch_queue_t)callbackQueue
|
|
completionBlock:(void(^)(_ASAsyncTransaction *, BOOL))completionBlock
|
|
{
|
|
if ((self = [self init])) {
|
|
if (callbackQueue == NULL) {
|
|
callbackQueue = dispatch_get_main_queue();
|
|
}
|
|
_callbackQueue = callbackQueue;
|
|
_completionBlock = [completionBlock copy];
|
|
|
|
_state = ASAsyncTransactionStateOpen;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
// Uncommitted transactions break our guarantees about releasing completion blocks on callbackQueue.
|
|
ASDisplayNodeAssert(_state != ASAsyncTransactionStateOpen, @"Uncommitted ASAsyncTransactions are not allowed");
|
|
}
|
|
|
|
#pragma mark -
|
|
#pragma mark Transaction Management
|
|
|
|
- (void)addAsyncOperationWithBlock:(asyncdisplaykit_async_transaction_async_operation_block_t)block
|
|
queue:(dispatch_queue_t)queue
|
|
completion:(asyncdisplaykit_async_transaction_operation_completion_block_t)completion
|
|
{
|
|
ASDisplayNodeAssertMainThread();
|
|
ASDisplayNodeAssert(_state == ASAsyncTransactionStateOpen, @"You can only add operations to open transactions");
|
|
|
|
[self _ensureTransactionData];
|
|
|
|
ASDisplayNodeAsyncTransactionOperation *operation = [[ASDisplayNodeAsyncTransactionOperation alloc] initWithOperationCompletionBlock:completion];
|
|
[_operations addObject:operation];
|
|
dispatch_group_async(_group, queue, ^{
|
|
@autoreleasepool {
|
|
if (_state != ASAsyncTransactionStateCanceled) {
|
|
dispatch_group_enter(_group);
|
|
block(^(id<NSObject> value){
|
|
operation.value = value;
|
|
dispatch_group_leave(_group);
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
- (void)addOperationWithBlock:(asyncdisplaykit_async_transaction_operation_block_t)block
|
|
queue:(dispatch_queue_t)queue
|
|
completion:(asyncdisplaykit_async_transaction_operation_completion_block_t)completion
|
|
{
|
|
ASDisplayNodeAssertMainThread();
|
|
ASDisplayNodeAssert(_state == ASAsyncTransactionStateOpen, @"You can only add operations to open transactions");
|
|
|
|
[self _ensureTransactionData];
|
|
|
|
ASDisplayNodeAsyncTransactionOperation *operation = [[ASDisplayNodeAsyncTransactionOperation alloc] initWithOperationCompletionBlock:completion];
|
|
[_operations addObject:operation];
|
|
dispatch_group_async(_group, queue, ^{
|
|
@autoreleasepool {
|
|
if (_state != ASAsyncTransactionStateCanceled) {
|
|
operation.value = block();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
- (void)addCompletionBlock:(asyncdisplaykit_async_transaction_completion_block_t)completion
|
|
{
|
|
__weak typeof(self) weakSelf = self;
|
|
[self addOperationWithBlock:^(){return (id<NSObject>)nil;} queue:_callbackQueue completion:^(id<NSObject> value, BOOL canceled) {
|
|
typeof(self) strongSelf = weakSelf;
|
|
completion(strongSelf, canceled);
|
|
}];
|
|
}
|
|
|
|
- (void)cancel
|
|
{
|
|
ASDisplayNodeAssertMainThread();
|
|
ASDisplayNodeAssert(_state != ASAsyncTransactionStateOpen, @"You can only cancel a committed or already-canceled transaction");
|
|
_state = ASAsyncTransactionStateCanceled;
|
|
}
|
|
|
|
- (void)commit
|
|
{
|
|
ASDisplayNodeAssertMainThread();
|
|
ASDisplayNodeAssert(_state == ASAsyncTransactionStateOpen, @"You cannot double-commit a transaction");
|
|
_state = ASAsyncTransactionStateCommitted;
|
|
|
|
if ([_operations count] == 0) {
|
|
// Fast path: if a transaction was opened, but no operations were added, execute completion block synchronously.
|
|
if (_completionBlock) {
|
|
_completionBlock(self, NO);
|
|
}
|
|
} else {
|
|
ASDisplayNodeAssert(_group != NULL, @"If there are operations, dispatch group should have been created");
|
|
dispatch_group_notify(_group, _callbackQueue, ^{
|
|
BOOL isCanceled = (_state == ASAsyncTransactionStateCanceled);
|
|
for (ASDisplayNodeAsyncTransactionOperation *operation in _operations) {
|
|
[operation callAndReleaseCompletionBlock:isCanceled];
|
|
}
|
|
if (_completionBlock) {
|
|
_completionBlock(self, isCanceled);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
#pragma mark -
|
|
#pragma mark Helper Methods
|
|
|
|
- (void)_ensureTransactionData
|
|
{
|
|
// Lazily initialize _group and _operations to avoid overhead in the case where no operations are added to the transaction
|
|
if (_group == NULL) {
|
|
_group = dispatch_group_create();
|
|
}
|
|
if (_operations == nil) {
|
|
_operations = [[NSMutableArray alloc] init];
|
|
}
|
|
}
|
|
|
|
@end
|