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 例項物件。