iOS開發全面解析多線程

來源:互聯網
上載者:User

iOS開發全面解析多線程

 

一.多線程基本概念

1. 進程
進程是指在系統中正在啟動並執行一個應用程式。每個進程之間是獨立的,每個進程均運行在其專用且受保護的記憶體空間內。

2. 線程
基本概念
1個進程要想執行任務,必須得有線程(每1個進程至少要有1條線程),線程是進程的基本執行單元,一個進程(程式)的所有任務都線上程中執行。

線程的串列
1個線程中任務的執行是串列的,如果要在1個線程中執行多個任務,那麼只能一個一個地按順序執行這些任務。也就是說,在同一時間內,1個線程只能執行1個任務。

3.多線程
基本概念
即1個進程中可以開啟多條線程,每條線程可以並行(同時)執行不同的任務

線程的並行
並行即同時執行。比如同時開啟3條線程分別下載3個檔案(分別是檔案A、檔案B、檔案C。

多線程並發執行的原理
在同一時間裡,CPU只能處理1條線程,只有1條線程在工作(執行)。多線程並發(同時)執行,其實是CPU快速地在多條線程之間調度(切換),如果CPU調度線程的時間足夠快,就造成了多線程並發執行的假象

4.多線程優缺點
優點
1)能適當提高程式的執行效率。
2)能適當提高資源使用率(CPU、記憶體利用率)
缺點
1)開啟線程需要佔用一定的記憶體空間(預設情況下,主線程佔用1M,子線程佔用512KB),如果開啟大量的線程,會佔用大量的記憶體空間,降低程式的效能。
2)線程越多,CPU在調度線程上的開銷就越大。
3)程式設計更加複雜:比如線程之間的通訊、多線程的資料共用

5.注意事項:
(1)不要同時開太多的線程(1~3條線程即可,不要超過5條)
(2) 主線程 : UI線程,顯示、重新整理UI介面,處理UI控制項的事件
(3) 子線程 : 後台線程,非同步線程
(4)不要把耗時的操作放在主線程,要放在子線程中執行

二、NSThread

1.建立和啟動線程的3種方式
(1)先建立,後啟動

// 建立
NSThread *thread = [[NSThread alloc] initWithTarget:self
selector:@selector(download:) object:nil];
// 啟動 [thread start];

(2)建立完自動啟動

[NSThread detachNewThreadSelector:@selector(download:) toTarget:self
withObject:nil];

(3) 隱式建立(自動啟動)

[self performSelectorInBackground:@selector(download:)
withObject:nil];

2.常見方法
(1) 獲得當前線程

+ (NSThread *)currentThread;

(2) 獲得主線程
+ (NSThread *)mainThread;

(3) 睡眠(暫停)線程

+(void)sleepUntilDate:(NSDate *)date;
+(void)sleepForTimeInterval:(NSTimeInterval)ti;

(4)設定線程的名字

-(void)setName:(NSString *)n;
-(NSString *)name;

線程同步
1.實質:為了防止多個線程搶奪同一個資源造成的資料安全問題

2.實現:給代碼加一個互斥鎖(同步鎖)
@synchronized(self) {
// 被鎖住的代碼
}

三、GCD

1.隊列和任務
(1) 任務 :需要執行什麼操作
用block來封裝任務

(2) 隊列 :存放任務
全域的並發隊列 : 可以讓任務並發執行

dispatch_queue_t queue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

自己建立的串列隊列 : 讓任務一個接著一個執行

dispatch_queue_t queue = dispatch_queue_create(“cn.heima.queue”,
NULL);

主隊列 : 讓任務在主線程執行

dispatch_queue_t queue = dispatch_get_main_queue();

2.執行任務的函數
(1) 同步執行 : 不具備開啟新線程的能力
dispatch_sync…

(2) 非同步執行 : 具備開啟新線程的能力
dispatch_async…

3.常見的組合

(1) 非同步函數+並發隊列:開啟多條線程,並發執行任務
(2) 非同步函數+串列隊列:開啟一條線程,串列執行任務
(3) 同步函數+並發隊列:不開線程,串列執行任務
(4) 同步函數+串列隊列:不開線程,串列執行任務
(5) 非同步函數+主隊列:不開線程,在主線程中串列執行任務
(6) 同步函數+主隊列:不開線程,串列執行任務(注意死結發生)
(7) 注意同步函數和非同步函數在執行順序上面的差異

注意事項: 同步函數往當前的串列隊列中新增工作,會卡住當前的線程,形成死結。

4.線程間的通訊<喎?http://www.bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vcD4KPGJsb2NrcXVvdGU+Cgk8cD5kaXNwYXRjaF9hc3luYyhkaXNwYXRjaF9nZXRfZ2xvYmFsX3F1ZXVlKERJU1BBVENIX1FVRVVFX1BSSU9SSVRZX0RFRkFVTFQsPGJyIC8+CgkwKSwgXns8YnIgLz4KCS8vINa00NC6xMqxtcTS7LK9stnX9y4uPC9wPgoJPGJsb2NrcXVvdGU+CgkJPHA+ZGlzcGF0Y2hfYXN5bmMoZGlzcGF0Y2hfZ2V0X21haW5fcXVldWUoKSw8YnIgLz4KCQleezxiciAvPgoJCS8vILvYtb3W98/fs8yjrNa00NBVScui0MKy2df3IH0pOyB9KTs8L3A+Cgk8L2Jsb2NrcXVvdGU+CjwvYmxvY2txdW90ZT4KPHA+PHN0cm9uZz41LkdDRLXEs6PTw7e9t6g8L3N0cm9uZz48YnIgLz4KPHN0cm9uZz6jqDGjqdHTs9nWtNDQPC9zdHJvbmc+PGJyIC8+CiZsdDsxJmd0OyBwZXJmb3JtU2VsZWN0b3I8YnIgLz4K0OjH8zogM8PruvPX1Lavu9i1vbWxx7DP37PMtffTw3NlbGa1xGRvd25sb2FkOre9t6ijrLKix9K0q7Xdss7K/aO6QCZyZHF1bztodHRwOi8vNTU1LmpwZyZyZHF1bzs8L3A+CjxwcmUgY2xhc3M9"brush:java;">[self performSelector:@selector(download:) withObject:@http://555.jpg afterDelay:3];

<2> dispatch_after

// 任務放到哪個隊列中執行 dispatch_queue_t queue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); double
delay = 3;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(delay * NSEC_PER_SEC)), queue, ^{
// 3秒後需要執行的任務
});

(2)一次性代碼

static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{
// 這裡面的代碼,在程式運行過程中,永遠只會執行1次 });

(3)柵欄函數(控制任務的執行順序)

dispatch_barrier_async(queue, ^{    NSLog(@--dispatch_barrier_async-);});

(4)快速迭代(開多個線程並發完成迭代操作)

dispatch_apply(subpaths.count, queue, ^(size_t index) {
});

(5)隊列組(同柵欄函數)

//建立隊列組
dispatch_group_t group = dispatch_group_create();
//隊列組中的任務執行完畢之後,執行該函數
dispatch_group_notify(dispatch_group_t group,
dispatch_queue_t queue,
dispatch_block_t block);

四、NSOperation和NSOperationQueue

1.基本概念:
NSOperation是對GCD的封裝, 兩個核心概念【隊列+操作】
2.基本使用
(1) NSOperation本身是抽象類別,只能只有它的子類
(2)三個子類分別是:NSBlockOperation、NSInvocationOperation以及自訂繼承自NSOperation的類
(3) NSOperation和NSOperationQueue結合使用實現多線程並發

3.隊列的類型
(1) 主隊列

[NSOperationQueue mainQueue] 添加到”主隊列”中的操作,都會放到主線程中執行

(2) 非主隊列

[[NSOperationQueue alloc] init] 添加到”非主隊列”中的操作,都會放到子線程中執行

4.隊列新增工作

-(void)addOperation:(NSOperation *)op;

-(void)addOperationWithBlock:(void (^)(void))block;

5.常見用法
(1) 設定最大並發數

- (NSInteger)maxConcurrentOperationCount;- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;

(2) 隊列的其他動作

取消所有的操作
-(void)cancelAllOperations;

暫停所有的操作
[queue setSuspended:YES];

恢複所有的操作
[queue setSuspended:NO];

6.操作之間的依賴(面試題)

NSOperation之間可以設定依賴來保證執行順序 [operationB addDependency:operationA];
// 操作B依賴於操作A,等操作A執行完畢後,才會執行操作B 注意:不能相互依賴,比如A依賴B,B依賴A 可以在不同queue的NSOperation之間建立依賴關係

7.線程之間的通訊

NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [queue
addOperationWithBlock:^{
// 1.執行一些比較耗時的操作
// 2.回到主線程
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
}];
}];

五、單例模式

1.ARC實現單例模式思路
(1) 在類的內部提供一個static修飾的全域變數
(2) 提供一個類方法,方便外界訪問
(3) 重寫+allocWithZone方法,保證永遠都只為單例對象分配一次記憶體空間
(4) 嚴謹起見,重寫-copyWithZone方法和-MutableCopyWithZone方法

(1) 建立一個類Factory 方法

@interface DataTool : NSObject
+ (instancetype)sharedDataTool; @end

@implementation DataTool

// 用來儲存唯一的單例對象
static id _instace;
// 重寫allocWithZone方法
+ (id)allocWithZone:(struct _NSZone *)zone {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instace = [super allocWithZone:zone];
});
return _instace; }

// sharedDataTool方法的實現+ (instancetype)sharedDataTool {    static dispatch_once_t onceToken;    dispatch_once(&onceToken, ^{        _instace = [[self alloc] init];    });    return _instace; }
// 重寫copyWithZone方法- (id)copyWithZone:(NSZone *)zone{    return _instace;}@end

2.MRC實現單例的思路
(1) 在類的內部提供一個static修飾的全域變數
(2) 提供一個類方法,方便外界訪問
(3) 重寫+allocWithZone方法,保證永遠都只為單例對象分配一次記憶體空間
(4) 嚴謹起見,重寫-copyWithZone方法和-MutableCopyWithZone方法
(5) 重寫release方法
(6) 重寫retain方法
(7) 建議在retainCount方法中返回一個最大值

// 聲明一個類Factory 方法@interface DataTool : NSObject+ (instancetype)sharedDataTool;@end

@implementation HMDataTool

// 用來儲存唯一的單例對象
static id _instace;
+ (id)allocWithZone:(struct _NSZone *)zone {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instace = [super allocWithZone:zone];
});
return _instace; }

 + (instancetype)sharedDataTool{    static dispatch_once_t onceToken;    dispatch_once(&onceToken, ^{        _instace = [[self alloc] init];    });    return _instace;}

// 重寫copyWithZone方法
- (id)copyWithZone:(NSZone *)zone {
return _instace; }

// 重寫release- (oneway void)release {   }
// 重寫retain- (id)retain {    return self;}
- (NSUInteger)retainCount {    return MAXFLOAT;}
// 重寫autorelease- (id)autorelease {    return self;}@end

3.判斷編譯器的環境:ARC還是MRC的方法

#if __has_feature(objc_arc)// 當前的編譯器環境是ARC#else// 當前的編譯器環境是MRC#endif
六、從其他線程回到主線程的方式

1.performSelectorOnMainThread

[self performSelectorOnMainThread:<#(SEL)#> withObject:<#(id)#> waitUntilDone:<#(BOOL)#>];

2.GCD

dispatch_async(dispatch_get_main_queue(), ^{});

3.NSOperationQueue

[[NSOperationQueue mainQueue] addOperationWithBlock:^{}];
七、類的初始化方法

1.+(void)load

當某個類第一次裝載到OC運行時系統(記憶體)時,就會調用 程式一啟動就會調用 程式運行過程中,只會調用1次

2.+(void)initialize

當某個類第一次被使用時(比如調用了類的某個方法),就會調用 並非程式一啟動就會調用

3.在程式運行過程中:1個類中的某個操作,只想執行1次,那麼這個操作放到+(void)load方法中最合適

八、cell的圖片下載

1.面試題
1> 如何防止一個url對應的圖片重複下載

“cell下載圖片思路 – 有沙箱緩衝”

2> SDWebImage的預設緩衝時間長度是多少?

1個星期

3> SDWebImage底層是怎麼實現的?

(1)無沙箱緩衝
實現步驟:
1.先緩衝需要的圖片
2.根據圖片的url去image中取圖片 有圖片 直接顯示到cell上
3.圖片不存在,顯示一個佔位圖片
4.根據圖片的url查看operations中是否存在下載操作
5.若下載操作存在,執行正在下載
6.不存在,建立下載操作放到operation中
7.下載完成,將操作從operation中移除,將圖片放到image中
8.重新整理表格

(2)有沙箱緩衝
1.根據圖片的URL去image中取圖片 存在 顯示到cell上
2.如果圖片不存在 檢查沙箱中是否有圖片 存在 顯示到cell上
3.如果不存在 顯示一張佔位圖片
4.根據圖片的URL檢查operation是否有下載操作 存在 繼續下載
5.如果不存在 建立下載操作 放到operation中
6.下載完畢 將操作從operation中移除
7.重新整理表格 按行重新整理
8.將圖片儲存到沙箱中

2.第三方架構SDWebImage的使用
(1) 常用方法

-(void)sd_setImageWithURL:(NSURL )url placeholderImage:(UIImage )placeholder;

- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options;
-(void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletionBlock)completedBlock;

-(void)sd_setImageWithURL:(NSURL )url placeholderImage:(UIImage )placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock
completed:(SDWebImageCompletionBlock)completedBlock;

(2) 記憶體處理:當app接收到記憶體警告時
// 當app接受到記憶體警告

–(void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
SDWebImageManager *mgr = [SDWebImageManager sharedManager];
// 1.取消正在下載的操作
[mgr cancelAll];
// 2.清除記憶體緩衝
[mgr.imageCache clearMemory]; }

(3) SDWebImageOptions

SDWebImageRetryFailed : 下載失敗後,會自動重新下載 SDWebImageLowPriority : 當進行中UI互動時,自動暫停內部的一些下載操作 SDWebImageRetryFailed | SDWebImageLowPriority : 擁有上面2個功能

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.