1. 程式人生 > >ReactiveCocoa 學習筆記十(RACScheduler)

ReactiveCocoa 學習筆記十(RACScheduler)

RACScheduler

該類用來控制任務的執行,但其是一個抽象類,真正執行操作的是其子類。

執行任務的許可權,其實與佇列許可權相對應。

typedef enum : long {
	RACSchedulerPriorityHigh = DISPATCH_QUEUE_PRIORITY_HIGH,
	RACSchedulerPriorityDefault = DISPATCH_QUEUE_PRIORITY_DEFAULT,
	RACSchedulerPriorityLow = DISPATCH_QUEUE_PRIORITY_LOW,
	RACSchedulerPriorityBackground = DISPATCH_QUEUE_PRIORITY_BACKGROUND,
} RACSchedulerPriority;

這裡還定義了一個型別 RACSchedulerRecursiveBlock ,是一個含有一個引數,並且沒有返回值的程式碼塊,其包含的引數同樣是一個程式碼塊,並且該程式碼塊沒有引數和返回值。

typedef void (^RACSchedulerRecursiveBlock)(void (^reschedule)(void));

該類提供了幾個類方法以獲取例項物件,而其中幾個實際返回的是子類的例項物件,並且該物件是全域性共享的。

//返回一個 RACImmediateScheduler 全域性例項物件,
//其會立刻執行提供的程式碼塊任務
+ (RACScheduler *)immediateScheduler;

//返回一個 RACTargetQueueScheduler 全域性例項物件,
//並且任務的執行佇列被指定為主佇列
+ (RACScheduler *)mainThreadScheduler;

//返回一個 RACSubscriptionScheduler 全域性例項物件,
//其有一個 RACScheduler 型別的屬性 backgroundScheduler ,
//如果 currentScheduler 為 nil 時,使用該屬性物件執行任務
+ (instancetype)subscriptionScheduler;

下面三個方法可歸結為第一個方法,最終都返回一個 RACTargetQueueScheduler 例項物件,所有的任務都會加入到全域性佇列中。

+ (RACScheduler *)schedulerWithPriority:(RACSchedulerPriority)priority name:(nullable NSString *)name;

+ (RACScheduler *)schedulerWithPriority:(RACSchedulerPriority)priority;

+ (RACScheduler *)scheduler;

下面的方法用來獲取當前儲存的 RACScheduler 例項物件,可知,當儲存值為空時,其會判斷是否返回指定主佇列的例項物件。

+ (RACScheduler *)currentScheduler {
	RACScheduler *scheduler = NSThread.currentThread.threadDictionary[RACSchedulerCurrentSchedulerKey];
	if (scheduler != nil) return scheduler;
	if ([self.class isOnMainThread]) return RACScheduler.mainThreadScheduler;

	return nil;
}

該類還定義了幾個抽象函式,其具體操作由子類實現。

//提供的程式碼塊任務會新增到相應的佇列中
- (nullable RACDisposable *)schedule:(void (^)(void))block;

//在指定的時間或之後執行提供的任務,該任務不會影響其他任務
- (nullable RACDisposable *)after:(NSDate *)date schedule:(void (^)(void))block;

//延遲指定時間執行所提供的任務,該方法實際會呼叫上面的方法
- (nullable RACDisposable *)afterDelay:(NSTimeInterval)delay schedule:(void (^)(void))block;

//在指定時間或之後執行提供的任務,並定時重複執行
- (nullable RACDisposable *)after:(NSDate *)date repeatingEvery:(NSTimeInterval)interval withLeeway:(NSTimeInterval)leeway schedule:(void (^)(void))block;

下面這個方法可以將遞迴任務自動轉換為迴圈任務,所以其可以反覆的呼叫自己。

- (nullable RACDisposable *)scheduleRecursiveBlock:(RACSchedulerRecursiveBlock)recursiveBlock;

該方法會執行提供的任務,並且會將當前例項物件暫存為當前執行緒的 scheduler ,而任務執行結束後,scheduler 會修改回原值或移除。

- (void)performAsCurrentScheduler:(void (^)(void))block {
	NSCParameterAssert(block != NULL);

	RACScheduler *previousScheduler = RACScheduler.currentScheduler;
	NSThread.currentThread.threadDictionary[RACSchedulerCurrentSchedulerKey] = self;

	@autoreleasepool {
		block();
	}

	if (previousScheduler != nil) {
		NSThread.currentThread.threadDictionary[RACSchedulerCurrentSchedulerKey] = previousScheduler;
	} else {
		[NSThread.currentThread.threadDictionary removeObjectForKey:RACSchedulerCurrentSchedulerKey];
	}
}

RACImmediateScheduler

RACImmediateScheduler 是 RACScheduler 的子類,其重寫了父類的方法,對於提供的任務會立刻執行。

- (RACDisposable *)schedule:(void (^)(void))block {
	NSCParameterAssert(block != NULL);

	block();
	return nil;
}

RACQueueScheduler

RACQueueScheduler 是 RACScheduler 的子類,其重寫了父類的方法,會將提供的任務加入指定的佇列非同步執行。

- (RACDisposable *)schedule:(void (^)(void))block {
	NSCParameterAssert(block != NULL);

	RACDisposable *disposable = [[RACDisposable alloc] init];

	dispatch_async(self.queue, ^{
		if (disposable.disposed) return;
		[self performAsCurrentScheduler:block];
	});

	return disposable;
}

RACTargetQueueScheduler

RACTargetQueueScheduler 是 RACQueueScheduler 的子類,該類重寫了父類的方法。

- (instancetype)initWithName:(NSString *)name targetQueue:(dispatch_queue_t)targetQueue {
	NSCParameterAssert(targetQueue != NULL);

	if (name == nil) {
		name = [NSString stringWithFormat:@"org.reactivecocoa.ReactiveObjC.RACTargetQueueScheduler(%s)", dispatch_queue_get_label(targetQueue)];
	}

	dispatch_queue_t queue = dispatch_queue_create(name.UTF8String, DISPATCH_QUEUE_SERIAL);
	if (queue == NULL) return nil;

	dispatch_set_target_queue(queue, targetQueue);

	return [super initWithName:name queue:queue];
}

在該初始化方法中,其主要是建立了一個竄行佇列,並且為該竄行佇列設定了目標佇列。

RACSubscriptionScheduler

RACSubscriptionScheduler 是 RACScheduler 的子類,其重寫了父類的方法,會將提供的任務加入指定的佇列非同步執行,當然,也可能是直接執行任務。

- (RACDisposable *)schedule:(void (^)(void))block {
	NSCParameterAssert(block != NULL);

	if (RACScheduler.currentScheduler == nil) return [self.backgroundScheduler schedule:block];

	block();
	return nil;
}

該類有一個屬性 backgroundScheduler ,當全域性變數 currentScheduler 為空時,該屬性便會被使用。

_backgroundScheduler = [RACScheduler scheduler];

backgroundScheduler 實質上是一個 RACTargetQueueScheduler 例項物件。