NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
[thread start];
// 線程一啟動,就會在線程thread中執行self的run方法
常見相關用法
+ (NSThread *)mainThread; // 獲得主線程
- (BOOL)isMainThread; // 是否為主線程
+ (BOOL)isMainThread; // 是否為主線程
// 獲取當前線程
NSThread *current = [NSThread currentThread];
// 線程的名字
- (void)setName:(NSString *)n;
- (NSString *)name;
其他創建線程方式
// 創建線程後自動啟動線程
[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
// 隱式創建並啟動線程
[self performSelectorInBackground:@selector(run) withObject:nil];
控制線程的狀態
// 啟動線程
- (void)start;
// 進入就緒狀態 -> 運行狀態。當線程任務執行完畢,自動進入死亡狀態
// 阻塞(暫停)線程
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
// 進入阻塞狀態
// 強制停止線程
+ (void)exit;
// 進入死亡狀態
// 注意:一旦線程停止(死亡)了,就不能再次開啟任務
@synchronized(鎖對象) { // 需要鎖定的代碼 }
// 注意:鎖定1份代碼只用1把鎖,用多把鎖是無效的
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;
// 用同步的方式執行任務
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
// queue:隊列
// block:任務
// 注意:使用sync函數往當前串行隊列中添加任務,會卡住當前的串行隊列。同步方式會阻塞當前隊列。
// 用異步的方式執行任務
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
// 在前面的任務執行結束後它才執行,而且它後面的任務等它執行完成之後才會執行
// 注意:這個queue不能是全局的並發隊列
同步和異步的區別
// 創建並發隊列
dispatch_queue_t queue = dispatch_queue_create("隊列名稱", DISPATCH_QUEUE_CONCURRENT)
// 第一個參數 const char *label 隊列名稱
// 第二個參數 dispatch_queue_attr_t attr 隊列的類型 DISPATCH_QUEUE_CONCURRENT 表示並發隊列
// 獲得全局的並發隊列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 第一個參數 dispatch_queue_priority_t priority 隊列的優先級
// 第二個參數 unsigned long flags 此參數暫時無用,用0即可
#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默認(中)
#define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 後台
串行隊列
// 創建串行隊列(隊列類型傳遞NULL或者DISPATCH_QUEUE_SERIAL)
dispatch_queue_t queue = dispatch_queue_create("隊列名稱", NULL);
// 獲得主隊列,主隊列也是串行隊列
dispatch_queue_t queue = dispatch_get_main_queue();
線程間的通信
// 從子線程回到主線程
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 執行耗時的異步操作...
dispatch_async(dispatch_get_main_queue(), ^{
// 回到主線程,執行UI刷新操作
});
});
延遲操作
[self performSelector:@selector(run) withObject:nil afterDelay:2.0];
// 2秒後再調用self的run方法
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 2秒後執行這裡的代碼...
});
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(test) userInfo:nil repeats:NO];
一次性代碼
// 使用dispatch_once函數能保證某段代碼在程序運行過程中只被執行1次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 只執行1次的代碼(這裡面默認是線程安全的)
});
快速迭代
// 使用dispatch_apply函數能進行快速迭代遍歷
dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index){
// 執行10次代碼,index順序不確定
});
隊列組
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 執行1個耗時的異步操作
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 執行1個耗時的異步操作
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 等前面的異步操作都執行完畢後,回到主線程...
});
// 在.m中保留一個全局的static的實例
static id _instance;
// 重寫allocWithZone:方法,在這裡創建唯一的實例(注意線程安全),alloc方法會調用allocWithZone:方法
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [super allocWithZone:zone];
});
return _instance;
}
// 提供1個類方法讓外界訪問唯一的實例
+ (instancetype)sharedInstance
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] init];
});
return _instance;
}
// 實現copyWithZone:方法
- (id)copyWithZone:(struct _NSZone *)zone
{
return _instance;
}
// 創建NSInvocationOperation對象
- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;
// 調用start方法開始執行操作
- (void)start;
// 一旦執行操作,就會調用target的sel方法
// 注意:默認情況下,調用了start方法後並不會開一條新線程去執行操作,而是在當前線程同步執行操作。只有將NSOperation放到一個NSOperationQueue中,才會異步執行操作
NSBlockOperation
// 創建NSBlockOperation對象
+ (id)blockOperationWithBlock:(void (^)(void))block;
// 通過addExecutionBlock:方法添加更多的操作
- (void)addExecutionBlock:(void (^)(void))block;
// 注意:只要NSBlockOperation封裝的操作數 > 1,就會異步執行操作
NSOperationQueue
// 添加操作到NSOperationQueue中
- (void)addOperation:(NSOperation *)op;
- (void)addOperationWithBlock:(void (^)(void))block;
相關操作
// 設置最大並發數
- (NSInteger)maxConcurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
// 取消隊列的所有操作
- (void)cancelAllOperations;
// 提示:也可以調用NSOperation的- (void)cancel方法取消單個操作
// 暫停和恢復隊列
- (void)setSuspended:(BOOL)b; // YES代表暫停隊列,NO代表恢復隊列
- (BOOL)isSuspended;
操作依賴
[operationB addDependency:operationA]; // 操作B依賴於操作A
操作的監聽
// 可以監聽一個操作的執行完畢
- (void (^)(void))completionBlock;
- (void)setCompletionBlock:(void (^)(void))block;
自定義NSOperation
NSDate *start = [NSDate date];
// 上下兩句代碼間放需要計算時間的程序
NSDate *end = [NSDate date];
NSLog(@"%f", [end timeIntervalSinceDate:start]);
CFTimeInterval begin = CFAbsoluteTimeGetCurrent();
// 上下兩句代碼間放需要計算時間的程序
CFTimeInterval end = CFAbsoluteTimeGetCurrent();
NSLog(@"%f", end - begin);
1、在GCD中,方法如果用異步函數可以開啟子線程做事情,該方法中的程序會順序執行到底,然後再返回去開啟子線程執行內部的操作。如果是同步函數,則不能開啟子線程,裡面的同步函數只能一個一個執行下去。
2、如果在主隊列中調用同步函數,容易造成死鎖。