iOS開發之多線程(2)—— Thread

版本

Xcode 11.5
Swift 5.2.2

簡介

一個Thread即爲一個線程.

方法屬性

OC中的屬性方法(Swift方法名類似):

#pragma mark - 屬性 
// 可以使用返回的字典來保存線程的特定數據. (這只是一個普通的字典, 用來保存所有開發者感興趣的數據.)
@property (readonly, retain) NSMutableDictionary *threadDictionary;
// 線程優先級
@property double threadPriority API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0)); // To be deprecated; use qualityOfService below
// 線程優先級 (枚舉常量)
@property NSQualityOfService qualityOfService API_AVAILABLE(macos(10.10), ios(8.0), watchos(2.0), tvos(9.0)); // read-only after the thread is started
// 保存的線程名字 (不明覺厲)
@property (nullable, copy) NSString *name API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
// 線程的堆內存大小字節數 (必須是4KB的倍數, 要使設置有用, 必須在start方法調用前設置.)
@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 (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));
// 線程是否已經調用cancel方法 (調用cancel後線程不會立即退出, 此時finished有可能爲NO)
@property (readonly, getter=isCancelled) BOOL cancelled API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));

#pragma mark - 類方法
// 當前線程 (類方法)
@property (class, readonly, strong) NSThread *currentThread;
// 是否主線程 (類方法)
@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));
// 是否多線程 (如果是通過非Cocoa的api開啓的線程, 比如POSIX或者Multiprocessing Services APIs, 被認爲不是多線程.)
+ (BOOL)isMultiThreaded;
// 線程休眠到aDate的時候 (在休眠期間run loop不處理事件)
+ (void)sleepUntilDate:(NSDate *)date;
// 休眠ti秒
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
// 強行停止線程 (應該避免調用此方法, 因爲它不會使線程有機會清理在執行過程中分配的任何資源.)
+ (void)exit;
// 獲取線程優先級 (0.0~1.0) (典型值是0.5, 但是由於優先級是由內核確定的, 因此不能保證此值實際上是多少)
+ (double)threadPriority;
// 設置線程優先級
+ (BOOL)setThreadPriority:(double)p;

#pragma mark - 對象方法
// 給線程發送取消信號, 最終何時取消由線程本身決定
- (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));
// 執行start方法後會自動調用main方法 (如果要繼承NSThread, 可以重寫main方法來執行新線程的主要部分)
- (void)main API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));	// thread body method

#pragma mark - 創建
// 創建新線程 (iOS 10+可用)
+ (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;
// 初始化NSThread對象
- (instancetype)init API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0)) NS_DESIGNATED_INITIALIZER;
// 初始化NSThread對象 (使用selector)
- (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));
// 初始化NSThread對象 (使用block, iOS 10+可用)
- (instancetype)initWithBlock:(void (^)(void))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));

#pragma mark - 線程切換
// 切換到主線程 (在主線程調用SEL方法), wait: 是否阻塞當前線程
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array;
// 同上 (線程模式爲kCFRunLoopCommonModes)
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
// 切換到指定線程 (在指定線程調用SEL方法)
- (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));
// 同上 (線程模式爲kCFRunLoopCommonModes)
- (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));
// 在新的後臺線程上調用SEL方法 (注意: 此方法創建新線程)
- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));

示例

創建一個子線程, 在子線程中改變value值, 然後回到主線程打印該value值.

OC

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [NSThread detachNewThreadSelector:@selector(changeValue) toTarget:self withObject:nil];
}


- (void)changeValue {
    
    NSLog(@"%s thread:%@, value=%d", __func__, [NSThread currentThread], self.value);
    self.value = 10;
    // 調用主線程
    [self performSelectorOnMainThread:@selector(logValue) withObject:nil waitUntilDone:NO];
}


- (void)logValue {
    
    NSLog(@"%s thread:%@, value=%d", __func__, [NSThread currentThread], self.value);
}

-----------------------------------------------------------------------------------------------------
log:
-[ViewController changeValue] thread:<NSThread: 0x60000262b1c0>{number = 7, name = (null)}, value=0
-[ViewController logValue] thread:<NSThread: 0x60000266d0c0>{number = 1, name = main}, value=10

Swift

class KKThread: NSObject {
    
    var value: Int = 0
    

    @objc func startThread() {
        
        Thread.detachNewThreadSelector(#selector(changeValue), toTarget: self, with: nil)
    }
    
    
    @objc func changeValue() {
        
        print("\(#function), thread:\(Thread.current), value=\(self.value)")
        self.value = 5
        // 調用主線程
        self.performSelector(onMainThread: #selector(logValue), with: nil, waitUntilDone: false)
    }
    
    
    @objc func logValue() {
        
        print("\(#function), thread:\(Thread.current), value=\(self.value)")
    }
}

注: 關於OC中調用Swift請移步iOS開發之Swift篇(15)—— Swift與Objective-C混編

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章