performSelector開頭的方法有不少,咱們簡單梳理一下ios
@protocol NSObject
......
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
......
@end
複製代碼
這時的performSelector是同步調用,能夠在主線程也能夠在其餘線程調用,可是和直接調用不一樣的是它會在運行時去找方法的實現,編譯時不校驗方法是否實現,通常和respondsToSelector
配合使用,咱們研究線程相關內容不涉及到它們macos
@interface NSObject (NSDelayedPerforming)
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray<NSRunLoopMode> *)modes;
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay;
+ (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget selector:(SEL)aSelector object:(nullable id)anArgument;
+ (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget;
@end
複製代碼
這是兩個異步調用函數,即便afterDelay
設置爲0仍然是異步調用,其實現邏輯是在RunLoop
中開啓一個計時器。這裏有兩個cancle
方法,能夠取消任務執行api
[self performSelector:@selector(fun) withObject:nil afterDelay:3];
[self performSelector:@selector(fun1) withObject:nil afterDelay:2];
- (void)fun{
NSLog(@"我是fun");
}
- (void)fun1{
[NSRunLoop cancelPreviousPerformRequestsWithTarget:self selector:@selector(fun) object:nil];;
}
複製代碼
延遲三秒以後執行方法fun
,可是2秒以後一個賤賤的方法取消了你的執行,因而fun
就沒有執行,爲了防止方法泄漏,最好在dealloc
方法中主動調用cancne
方法,防止內存泄漏markdown
注意由於自線程的runloop默認是不開啓的,因此在子線程執行的時候要手動開啓RunLoop,例如這樣是不執行的數據結構
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self performSelector:@selector(fun) withObject:nil afterDelay:1];
});
- (void)fun{
NSLog(@"我是fun");
}
複製代碼
修改一番多線程
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self performSelector:@selector(fun) withObject:nil afterDelay:1];
[[NSRunLoop currentRunLoop] run];
});
- (void)fun{
NSLog(@"我是fun");
}
複製代碼
這樣就能夠正常執行fun
了異步
@interface NSObject (NSThreadPerformAdditions)
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
// equivalent to the first method with kCFRunLoopCommonModes
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
// equivalent to the first method with kCFRunLoopCommonModes
- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
@end
複製代碼
這幾個方法咱們須要重點關注一下。async
前兩個方法是在主線程執行,waitUntilDone
設置爲YES
會阻塞當前線程,主線程執行完selector
以後當前線程繼續執行,設置爲NO
不會阻塞當前線程。modes
設置RunLoop的mode,例如若是咱們設置kCFRunLoopDefaultMode
那麼當列表滾動時就不會執行selector
,若是咱們設置kCFRunLoopCommonModes
就能夠正常執行。沒有modes
參數的方法默認設置爲kCFRunLoopCommonModes
函數
三四個方法和前兩個相似,只不過是指定線程來執行,若是指定主線程,那麼就和前兩個方法效果同樣。oop
第五個方法開啓子線程在後臺運行,隱式建立並啓動線程
和GCD相比NSThread
須要咱們來管理線程的生命週期,因此咱們更多的會選擇使用更簡單的GCD,可是NSThread
的一些方法咱們仍是須要常常用到的,好比:
[NSThread currentThread]
獲取當前線程[NSThread isMainThread]
判斷當前線程是不是主線程咱們看一下NSThread.h
還有那些咱們熟悉的方法
currentThread
@property (class, readonly, strong) NSThread *currentThread;
複製代碼
+ (void)detachNewThreadWithBlock:(void (^)(void))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;
複製代碼
+ (BOOL)isMultiThreaded;
複製代碼
@property (readonly, retain) NSMutableDictionary *threadDictionary;
複製代碼
好比
NSThread *thread = [[NSThread alloc]initWithBlock:^{}];
NSMutableDictionary *dic = [thread threadDictionary];
[dic setValue:@"aKey" forKey:@"aValue"];
NSLog(@"threadDictionary == %@",[thread threadDictionary]);
複製代碼
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
複製代碼
+ (void)exit;
複製代碼
+ (double)threadPriority;
+ (BOOL)setThreadPriority:(double)p;
@property double threadPriority API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0)); // To be deprecated; use qualityOfService below
複製代碼
@property (nullable, copy) NSString *name API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
複製代碼
iOS
下主要成本包括:內核數據結構(大約1KB
)、棧空間(子線程512KB
、主線程1MB
,也可使用setStackSize
:設置,但必須是4K
的倍數,並且最小是16K
),建立線程大約須要90毫秒
的建立時間)@property NSUInteger stackSize API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
複製代碼
@property (readonly) BOOL isMainThread API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
複製代碼
@property (class, readonly) BOOL isMainThread API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0)); // reports whether current thread is main
複製代碼
@property (class, readonly, strong) NSThread *mainThread API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
複製代碼
start
方法- (instancetype)init API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0)) NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
- (instancetype)initWithBlock:(void (^)(void))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
複製代碼
@property (readonly, getter=isExecuting) BOOL executing API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
@property (readonly, getter=isFinished) BOOL finished API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
@property (readonly, getter=isCancelled) BOOL cancelled API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
複製代碼
- (void)cancel API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
- (void)start API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
- (void)main API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0)); // thread body method
複製代碼
場景:建立一個子線程執行耗時操做,執行結束之後回調主線程刷新頁面
NSThread *thread = [[NSThread alloc]initWithBlock:^{
sleep(2);
[self performSelectorOnMainThread:@selector(fun) withObject:nil waitUntilDone:YES];
}];
[thread start];
複製代碼
更復雜的操做就須要藉助鎖了;