NSRunLoop事件迴路及多線程
一、多線程
每一個iOS應用程序中都有一個主線程用來更新UI界面、處理用戶的觸摸事件、解析網絡下載的數據,因此不能把一些太耗時的操作(比如網絡下載數據)放在主線程中執行,不然會造成主線程堵塞(出現界面卡死,防止界面假死),帶來極壞的用戶體驗。
iOS的解決方案就是將那些耗時的操作放到另外一個線程中去執行,多線程異步編程是防止主線程堵塞,增加運行效率的最佳方法
異步:多個線程 同時執行
同步:線程排隊執行
並行 —》異步
串行—》同步
多線程技術
1、異步下載數據,是多線程技術的一個比較常見的應用場景
2、多線程技術使用場景: app中有耗時的操作或功能(1、客戶端與服務端交互;2、從數據庫中一次性讀取大量數據 3、對大量數據的解析過程),需要在主線程之外,單獨開闢一個新的線程(子線程/工作線程)來執行
iOS所支持的多線程編程方法:
NSThread
NSOperation & NSOperationQueue
GCD
1.怎麼創建線程
a.
// 創建一個線程 但是這個線程不會自動執行
NSThread *t = [[NSThread alloc] initWithTarget:self selector:@selector(threadMain1:) object:n];
// 開始運行線程 手動開啓
[t start];
b.
// 線程創建後 就會自動運行
[NSThread detachNewThreadSelector:@selector(threadMain0:) toTarget:self withObject:n];
2.界面假死
主線程下載數據 會造成界面卡死
3.監聽線程結束
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(threadExit:) name:NSThreadWillExitNotification object:nil];
4.多個線程之間的通信
[t0 cancel];
if ([t isCancelled]){…}
退出/結束線程
[NSThread exit]; // 或者是return;
5.線程鎖
NSLock 互斥鎖
避免多個線程同時修改同一資源
修改數據庫寫法
6.線程修改進度條
UI主線程刷新UI界面
[self performSelectorOnMainThread:@selector(refreshUI:) withObject:@(i) waitUntilDone:NO];
dispatch_async(dispatch_get_main_queue(), ^{
[self refreshUI:1];
});
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(updateImage:) object:image];
[[NSOperationQueue mainQueue] addOperation:operation];
什麼是主線程? 凡是不是在普通/工作線程裏面的都是在 UI 主線程中
7.自定義線程
自定義的線程 要繼承與NSthread
需要實現- main 線程主函數
擴展函數
//獲取當前線程
+ (NSThread *)currentThread;
//創建啓動線程
+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)argument;
//判斷是否是多線程
+ (BOOL)isMultiThreaded;
- (NSMutableDictionary *)threadDictionary;
//線程休眠 NSDate 給一個休眠到什麼時候
+ (void)sleepUntilDate:(NSDate *)date;
//線程休眠時間
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
//結束/退出當前線程
+ (void)exit;
//獲取當前線程優先級
+ (double)threadPriority;
//設置當前線程的優先級 一般我們不設置
//自己創建的線程優先級是 0.5 主線程是0.8左右
//優先級返回 0---1.0
//設置優先級
+ (BOOL)setThreadPriority:(double)p;
//獲取指定線程的優先級
- (double)threadPriority NS_AVAILABLE(10_6, 4_0);
- (void)setThreadPriority:(double)p NS_AVAILABLE(10_6, 4_0);
//設置線程的名字
- (void)setName:(NSString *)n NS_AVAILABLE(10_5, 2_0);
- (NSString *)name NS_AVAILABLE(10_5, 2_0);
//判斷指定的線程是否是 主線程
- (BOOL)isMainThread NS_AVAILABLE(10_5, 2_0);
//判斷當前線程是否是主線程
+ (BOOL)isMainThread NS_AVAILABLE(10_5, 2_0); // reports whether current thread is main
//獲取主線程
+ (NSThread *)mainThread NS_AVAILABLE(10_5, 2_0);
- (id)init NS_AVAILABLE(10_5, 2_0); // designated initializer
- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument NS_AVAILABLE(10_5, 2_0);
//指定線程是否在執行
- (BOOL)isExecuting NS_AVAILABLE(10_5, 2_0);
//線程是否完成
- (BOOL)isFinished NS_AVAILABLE(10_5, 2_0);
//線程是否被取消 (是否給當前線程發過取消信號)
- (BOOL)isCancelled NS_AVAILABLE(10_5, 2_0);
//發送線程取消信號的 最終線程是否結束 由 線程本身決定
- (void)cancel NS_AVAILABLE(10_5, 2_0);
//啓動線程
- (void)start NS_AVAILABLE(10_5, 2_0);
//線程主函數 在線程中執行的函數 都要在-main函數中調用
- (void)main NS_AVAILABLE(10_5, 2_0); // thread body metho
二、任務隊列
NSOperation
NSThread 操作線程最基本的類, 得到的子線程的效率要低於NSOperation
NSOperation 是一個輕量級的線程
NSOperationQueue 線程池,操作隊列
以任務爲導向的管理線程機制,將操作(任務)放入到線程池裏,會自動執行,弱化線程的概念。(任務:可以認爲是線程)
自定義任務
NSOperation 抽象類,如果想創建自己的任務,就要繼承NSOperation,來實現自己的類
重寫main函數!
三、GCD(推薦使用)
GCD 全稱Grand Central Dispatch(隊列調度)
是一套低層API,提供了⼀種新的方法來進⾏併發程序編寫。
從基本功能上講,GCD有點像NSOperationQueue,他們都允許程序將任務切分爲多個單一任務,然後提交⾄至⼯工作隊列來併發地或者串⾏行地執⾏行。
GCD是C實現,⽐NSOpertionQueue更底層更高效,並且它不是Cocoa框架的一部分
併發任務會像NSOperationQueue那樣基於系統負載來合適地併發進⾏,串⾏行隊列同一時間只執行單一任務
GCD的API很大程度上基於block
1.主線程隊列
主線程隊列 內部執行任務是串行的同步操作
主線程隊列不需要我們創建,通過dispatch_get_main_queue()方法獲得
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
[self taskThread1];
});
或者
dispatch_async(dispatch_get_main_queue(), ^{
[self taskThread2];
});
2.創建私有隊列 用戶隊列/串行隊列
DISPATCH_QUEUE_SERIAL串行
// C接口,創建一個私有隊列 ,隊列名是一個C字符串,沒有特別的要求,Apple建議用倒裝的標識符來表示(這個名字,更多用於調試)
私有隊列內部也是串行操作
dispatch_queue_t queue = dispatch_queue_create("com.qianfeng", NULL);
dispatch_async(queue, ^{
[self taskThread2];
});
// 我們自己創建的隊列,我們需要自己銷燬
//dispatch_release(queue);
非arc 需要銷燬
3.全局隊列
// 並行隊列(全局)不需要我們創建,通過dispatch_get_global_queue()方法獲得
// 三個可用隊列
// 第一個參數是選取按個全局隊列,一般採用DEFAULT,默認優先級隊列
// 第二個參數是保留標誌,目前的版本沒有任何用處(不代表以後版本),直接設置爲0就可以了
// DISPATCH_QUEUE_PRIORITY_HIGH
// DISPATCH_QUEUE_PRIORITY_DEFAULT
// DISPATCH_QUEUE_PRIORITY_LOW
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
常用: 在全局隊列裏增加佔用時間很長的block(數據下載,文件操作,數據庫操作),在主隊列裏刷新UI(刷新UI,務必要在主線程進行)
NSRunLoop 事件的迴路,是ios程序中實現異步事件處理的核心,每個線程都由一個迴路來控制
currentRunLoop 拿到控制當前線程的迴路, 通過迴路來維持當前線程的活躍狀態,暫停當前線程,直到數據下載完成
while (!_isDone) {
//線程會阻塞
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];
NSLog(@"任務中");
//當下載完成之後 另外一個下載線程通知當前線程,這時當前線程 來了輸入源,NSRunloop 就會退出
} ;//只有下載完成 這種情況 纔會NSRunloop真正退出 否則其他情況使NSRunloop 退出之後 _isDone不是yes 那麼 NSRunloop 又會繼續 run
每一個iOS應用程序中都有一個主線程用來更新UI界面、處理用戶的觸摸事件、解析網絡下載的數據,因此不能把一些太耗時的操作(比如網絡下載數據)放在主線程中執行,不然會造成主線程堵塞(出現界面卡死,防止界面假死),帶來極壞的用戶體驗。
iOS的解決方案就是將那些耗時的操作放到另外一個線程中去執行,多線程異步編程是防止主線程堵塞,增加運行效率的最佳方法
異步:多個線程 同時執行
同步:線程排隊執行
並行 —》異步
串行—》同步
多線程技術
1、異步下載數據,是多線程技術的一個比較常見的應用場景
2、多線程技術使用場景: app中有耗時的操作或功能(1、客戶端與服務端交互;2、從數據庫中一次性讀取大量數據 3、對大量數據的解析過程),需要在主線程之外,單獨開闢一個新的線程(子線程/工作線程)來執行
iOS所支持的多線程編程方法:
NSThread
NSOperation & NSOperationQueue
GCD
1.怎麼創建線程
a.
// 創建一個線程 但是這個線程不會自動執行
NSThread *t = [[NSThread alloc] initWithTarget:self selector:@selector(threadMain1:) object:n];
// 開始運行線程 手動開啓
[t start];
b.
// 線程創建後 就會自動運行
[NSThread detachNewThreadSelector:@selector(threadMain0:) toTarget:self withObject:n];
2.界面假死
主線程下載數據 會造成界面卡死
3.監聽線程結束
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(threadExit:) name:NSThreadWillExitNotification object:nil];
4.多個線程之間的通信
[t0 cancel];
if ([t isCancelled]){…}
退出/結束線程
[NSThread exit]; // 或者是return;
5.線程鎖
NSLock 互斥鎖
避免多個線程同時修改同一資源
修改數據庫寫法
6.線程修改進度條
UI主線程刷新UI界面
[self performSelectorOnMainThread:@selector(refreshUI:) withObject:@(i) waitUntilDone:NO];
dispatch_async(dispatch_get_main_queue(), ^{
[self refreshUI:1];
});
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(updateImage:) object:image];
[[NSOperationQueue mainQueue] addOperation:operation];
什麼是主線程? 凡是不是在普通/工作線程裏面的都是在 UI 主線程中
7.自定義線程
自定義的線程 要繼承與NSthread
需要實現- main 線程主函數
擴展函數
//獲取當前線程
+ (NSThread *)currentThread;
//創建啓動線程
+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)argument;
//判斷是否是多線程
+ (BOOL)isMultiThreaded;
- (NSMutableDictionary *)threadDictionary;
//線程休眠 NSDate 給一個休眠到什麼時候
+ (void)sleepUntilDate:(NSDate *)date;
//線程休眠時間
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
//結束/退出當前線程
+ (void)exit;
//獲取當前線程優先級
+ (double)threadPriority;
//設置當前線程的優先級 一般我們不設置
//自己創建的線程優先級是 0.5 主線程是0.8左右
//優先級返回 0---1.0
//設置優先級
+ (BOOL)setThreadPriority:(double)p;
//獲取指定線程的優先級
- (double)threadPriority NS_AVAILABLE(10_6, 4_0);
- (void)setThreadPriority:(double)p NS_AVAILABLE(10_6, 4_0);
//設置線程的名字
- (void)setName:(NSString *)n NS_AVAILABLE(10_5, 2_0);
- (NSString *)name NS_AVAILABLE(10_5, 2_0);
//判斷指定的線程是否是 主線程
- (BOOL)isMainThread NS_AVAILABLE(10_5, 2_0);
//判斷當前線程是否是主線程
+ (BOOL)isMainThread NS_AVAILABLE(10_5, 2_0); // reports whether current thread is main
//獲取主線程
+ (NSThread *)mainThread NS_AVAILABLE(10_5, 2_0);
- (id)init NS_AVAILABLE(10_5, 2_0); // designated initializer
- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument NS_AVAILABLE(10_5, 2_0);
//指定線程是否在執行
- (BOOL)isExecuting NS_AVAILABLE(10_5, 2_0);
//線程是否完成
- (BOOL)isFinished NS_AVAILABLE(10_5, 2_0);
//線程是否被取消 (是否給當前線程發過取消信號)
- (BOOL)isCancelled NS_AVAILABLE(10_5, 2_0);
//發送線程取消信號的 最終線程是否結束 由 線程本身決定
- (void)cancel NS_AVAILABLE(10_5, 2_0);
//啓動線程
- (void)start NS_AVAILABLE(10_5, 2_0);
//線程主函數 在線程中執行的函數 都要在-main函數中調用
- (void)main NS_AVAILABLE(10_5, 2_0); // thread body metho
二、任務隊列
NSOperation
NSThread 操作線程最基本的類, 得到的子線程的效率要低於NSOperation
NSOperation 是一個輕量級的線程
NSOperationQueue 線程池,操作隊列
以任務爲導向的管理線程機制,將操作(任務)放入到線程池裏,會自動執行,弱化線程的概念。(任務:可以認爲是線程)
自定義任務
NSOperation 抽象類,如果想創建自己的任務,就要繼承NSOperation,來實現自己的類
重寫main函數!
三、GCD(推薦使用)
GCD 全稱Grand Central Dispatch(隊列調度)
是一套低層API,提供了⼀種新的方法來進⾏併發程序編寫。
從基本功能上講,GCD有點像NSOperationQueue,他們都允許程序將任務切分爲多個單一任務,然後提交⾄至⼯工作隊列來併發地或者串⾏行地執⾏行。
GCD是C實現,⽐NSOpertionQueue更底層更高效,並且它不是Cocoa框架的一部分
併發任務會像NSOperationQueue那樣基於系統負載來合適地併發進⾏,串⾏行隊列同一時間只執行單一任務
GCD的API很大程度上基於block
1.主線程隊列
主線程隊列 內部執行任務是串行的同步操作
主線程隊列不需要我們創建,通過dispatch_get_main_queue()方法獲得
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
[self taskThread1];
});
或者
dispatch_async(dispatch_get_main_queue(), ^{
[self taskThread2];
});
2.創建私有隊列 用戶隊列/串行隊列
DISPATCH_QUEUE_SERIAL串行
// C接口,創建一個私有隊列 ,隊列名是一個C字符串,沒有特別的要求,Apple建議用倒裝的標識符來表示(這個名字,更多用於調試)
私有隊列內部也是串行操作
dispatch_queue_t queue = dispatch_queue_create("com.qianfeng", NULL);
dispatch_async(queue, ^{
[self taskThread2];
});
// 我們自己創建的隊列,我們需要自己銷燬
//dispatch_release(queue);
非arc 需要銷燬
3.全局隊列
// 並行隊列(全局)不需要我們創建,通過dispatch_get_global_queue()方法獲得
// 三個可用隊列
// 第一個參數是選取按個全局隊列,一般採用DEFAULT,默認優先級隊列
// 第二個參數是保留標誌,目前的版本沒有任何用處(不代表以後版本),直接設置爲0就可以了
// DISPATCH_QUEUE_PRIORITY_HIGH
// DISPATCH_QUEUE_PRIORITY_DEFAULT
// DISPATCH_QUEUE_PRIORITY_LOW
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
常用: 在全局隊列裏增加佔用時間很長的block(數據下載,文件操作,數據庫操作),在主隊列裏刷新UI(刷新UI,務必要在主線程進行)
NSRunLoop 事件的迴路,是ios程序中實現異步事件處理的核心,每個線程都由一個迴路來控制
currentRunLoop 拿到控制當前線程的迴路, 通過迴路來維持當前線程的活躍狀態,暫停當前線程,直到數據下載完成
while (!_isDone) {
//線程會阻塞
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];
NSLog(@"任務中");
//當下載完成之後 另外一個下載線程通知當前線程,這時當前線程 來了輸入源,NSRunloop 就會退出
} ;//只有下載完成 這種情況 纔會NSRunloop真正退出 否則其他情況使NSRunloop 退出之後 _isDone不是yes 那麼 NSRunloop 又會繼續 run
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.