你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS開發全面解析多線程

iOS開發全面解析多線程

編輯: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.線程間的通信<喎?/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) 創建一個類工廠方法

@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方法中返回一個最大值

// 聲明一個類工廠方法
@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個功能

 

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved