123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- /*
- * Copyright (c) 2014, 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 "OSSCancellationToken.h"
- #import "OSSCancellationTokenRegistration.h"
- NS_ASSUME_NONNULL_BEGIN
- @interface OSSCancellationToken ()
- @property (nullable, nonatomic, strong) NSMutableArray *registrations;
- @property (nonatomic, strong) NSObject *lock;
- @property (nonatomic) BOOL disposed;
- @end
- @interface OSSCancellationTokenRegistration (OSSCancellationToken)
- + (instancetype)registrationWithToken:(OSSCancellationToken *)token delegate:(OSSCancellationBlock)delegate;
- - (void)notifyDelegate;
- @end
- @implementation OSSCancellationToken
- @synthesize cancellationRequested = _cancellationRequested;
- #pragma mark - Initializer
- - (instancetype)init {
- self = [super init];
- if (!self) return self;
- _registrations = [NSMutableArray array];
- _lock = [NSObject new];
- return self;
- }
- #pragma mark - Custom Setters/Getters
- - (BOOL)isCancellationRequested {
- @synchronized(self.lock) {
- [self throwIfDisposed];
- return _cancellationRequested;
- }
- }
- - (void)cancel {
- NSArray *registrations;
- @synchronized(self.lock) {
- [self throwIfDisposed];
- if (_cancellationRequested) {
- return;
- }
- [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(cancelPrivate) object:nil];
- _cancellationRequested = YES;
- registrations = [self.registrations copy];
- }
- [self notifyCancellation:registrations];
- }
- - (void)notifyCancellation:(NSArray *)registrations {
- for (OSSCancellationTokenRegistration *registration in registrations) {
- [registration notifyDelegate];
- }
- }
- - (OSSCancellationTokenRegistration *)registerCancellationObserverWithBlock:(OSSCancellationBlock)block {
- @synchronized(self.lock) {
- OSSCancellationTokenRegistration *registration = [OSSCancellationTokenRegistration registrationWithToken:self delegate:[block copy]];
- [self.registrations addObject:registration];
- return registration;
- }
- }
- - (void)unregisterRegistration:(OSSCancellationTokenRegistration *)registration {
- @synchronized(self.lock) {
- [self throwIfDisposed];
- [self.registrations removeObject:registration];
- }
- }
- // Delay on a non-public method to prevent interference with a user calling performSelector or
- // cancelPreviousPerformRequestsWithTarget on the public method
- - (void)cancelPrivate {
- [self cancel];
- }
- - (void)cancelAfterDelay:(int)millis {
- [self throwIfDisposed];
- if (millis < -1) {
- [NSException raise:NSInvalidArgumentException format:@"Delay must be >= -1"];
- }
- if (millis == 0) {
- [self cancel];
- return;
- }
- @synchronized(self.lock) {
- [self throwIfDisposed];
- [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(cancelPrivate) object:nil];
- if (self.cancellationRequested) {
- return;
- }
- if (millis != -1) {
- double delay = (double)millis / 1000;
- [self performSelector:@selector(cancelPrivate) withObject:nil afterDelay:delay];
- }
- }
- }
- - (void)dispose {
- @synchronized(self.lock) {
- if (self.disposed) {
- return;
- }
- [self.registrations makeObjectsPerformSelector:@selector(dispose)];
- self.registrations = nil;
- self.disposed = YES;
- }
- }
- - (void)throwIfDisposed {
- if (self.disposed) {
- [NSException raise:NSInternalInconsistencyException format:@"Object already disposed"];
- }
- }
- @end
- NS_ASSUME_NONNULL_END
|