多線程2
- GCD隊列組:
- 基本使用:
//0.創(chuàng)建隊列組
dispatch_group_t group = dispatch_group_create();
//1.創(chuàng)建隊列
dispatch_queue_t queue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
//2.添加任務(wù)
//dispatch_async:1)封裝任務(wù)&2)提交任務(wù)到隊列
//dispatch_group_async:1)封裝任務(wù)&2)提交任務(wù)到隊列&3)把當(dāng)前的任務(wù)的執(zhí)行情況納入到隊列組的監(jiān)聽范圍中
dispatch_group_async(group,queue, ^{
NSLog(@"download1---%@",[NSThread currentThread]);
});
- 常用函數(shù)
// 兩者配合使用,后面的異步任務(wù)被監(jiān)聽
dispatch_group_enter(group);
dispatch_group_leave(group);
// 當(dāng)隊列中的任務(wù)執(zhí)行完后執(zhí)行block
dispatch_group_notify(<#dispatch_group_t group#>, <#dispatch_queue_t queue#>, <#^(void)block#>)
// 一直到前面的代碼塊都執(zhí)行完,下面的代碼塊才執(zhí)行
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
- 隊列和組隊列的區(qū)別
- 隊列:封裝任務(wù),添加任務(wù)到隊列
- 組隊列:封裝任務(wù),添加任務(wù)到隊列,添加隊列到組
- 單例模式設(shè)計:
- 設(shè)計分析:
//1.靜態(tài)變量
static XMGTool *_instance;
//2.重寫分配空間的方法(alloc會重寫allocWithZone方法)
//alloc --->allocWithZone
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
//解決安全問題
/*
@synchronized(self) {
if (_instance == nil) {
_instance = [super allocWithZone:zone];
}
}
*/
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [super allocWithZone:zone];
});
return _instance;
}
//3.提供類方法
+(instancetype)shareXMGTool
{
return [[self alloc]init];
}
//4.嚴(yán)謹(jǐn)
-(id)copyWithZone:(NSZone *)zone
{
return _instance;
}
-(id)mutableCopyWithZone:(NSZone *)zone
{
return _instance;
}
NSOpreation認(rèn)識學(xué)習(xí):
-
使用方法:
- NSInvocationOperation方法:
1.封裝操作 NSInvocationOperation *op1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download1) object:nil]; 2.開始操作 [op1 start];- NSBlockOperation方法:
//1.封裝操作 NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"1---%@",[NSThread currentThread]); }]; //追加操作 //如果操作里面的任務(wù)數(shù)量大于一,那么會開子線程一起執(zhí)行 [op3 addExecutionBlock:^{ NSLog(@"4---%@",[NSThread currentThread]); }]; //2.開始操作 [op1 start];- 自定義NSOpreation子類
多圖下載案例總結(jié):
項目設(shè)計思路:框架搭建(XMGApp存放模型數(shù)據(jù))->解決圖片重復(fù)下載問題(內(nèi)存緩存->磁盤緩存)->界面運(yùn)行卡頓問題解決(將圖片下載等耗時操作放到子線程中)->隊列重復(fù)創(chuàng)建問題(懶加載隊列)->數(shù)據(jù)錯亂問題解決(將每次下載的任務(wù)都添加到內(nèi)存中,并在下一次下載的時候檢查內(nèi)存是否有相應(yīng)任務(wù))->圖片不顯示問題解決(刷新每個cell)->cell重復(fù)使用(清空設(shè)置完的圖片或者設(shè)置占位圖片)
框架搭建:省略
-
圖片重復(fù)下載問題解決:
1.檢查內(nèi)存緩存中的圖片,并往內(nèi)存緩存中設(shè)置圖片 UIImage *image = [self.images objectForKey:appM.icon]; [self.images setObject:image forKey:appM.icon]; 2.檢查磁盤緩存中的圖片,并往磁盤緩存中設(shè)置圖片 NSString *cachesPath =[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; //得到圖片的名稱 NSString *filename = [appM.icon lastPathComponent]; //拼接文件的全路徑 NSString *fullPath = [cachesPath stringByAppendingPathComponent:filename]; //去檢查磁盤緩存 NSData *data = [NSData dataWithContentsOfFile:fullPath]; //把圖片保存到磁盤緩存(圖片不能直接寫入file中,需要變?yōu)槎M(jìn)制數(shù)據(jù)) [data writeToFile:fullPath atomically:YES]; 界面運(yùn)行卡頓問題解決:
```objc
將下載任務(wù)放到子線程中
NSBlockOperation dowbloadOperation = [NSBlockOperation blockOperationWithBlock:^{
......
}];
[self.queue addOperation:dowbloadOperation];
```
- 隊列重復(fù)創(chuàng)建問題解決:
```objc
-(NSOperationQueue *)queue
{
if (_queue == nil) {
_queue = [[NSOperationQueue alloc]init];
_queue.maxConcurrentOperationCount = 5;
}
return _queue;
}
```
- 數(shù)據(jù)錯亂問題解決:
1.懶加載任務(wù)字典,存放任務(wù)
-(NSMutableDictionary *)operations
{
if (_operations == nil) {
_operations = [NSMutableDictionary dictionary];
}
return _operations;
}
2.檢查操作緩存
NSBlockOperation *dowbloadOperation = [self.operations objectForKey:appM.icon];
3.添加操作到緩存中
[self.operations setObject:dowbloadOperation forKey:appM.icon];
- 圖片不顯示問題解決:
```objc
//設(shè)置圖片([tableView reloadData];刷新整個tableView cell.imageView.image = image;storyboard中的cell中imageView尺寸默認(rèn)為0)
[[NSOperationQueue mainQueue]addOperationWithBlock:^{
//刷新指定的行
[tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationMiddle];
}];
```
- cell復(fù)用問題解決:
```objc
//清空圖片或者是設(shè)置占位圖片
cell.imageView.image = [UIImage imageNamed:@"Snip20200808_172"];
```
- 項目運(yùn)行報錯(超時或找不到圖片):
if (image == nil) {
//把操作從操作緩存中移除
[self.operations removeObjectForKey:appM.icon];
return ;
}
- 內(nèi)存警告問題解決:
-(void)didReceiveMemoryWarning
{
//移除內(nèi)存緩存
[self.images removeAllObjects];
//取消隊列中的操作
[self.queue cancelAllOperations];
}