簡介
NSOperation的作用
配合使用NSOperation和NSOperationQueue也能實(shí)現(xiàn)多線程編程
NSOperation和NSOperationQueue實(shí)現(xiàn)多線程的具體步驟
先將需要執(zhí)行的操作封裝到一個(gè)NSOperation對象中
然后將NSOperation對象添加到NSOperationQueue中
系統(tǒng)會(huì)自動(dòng)將NSOperationQueue中的NSOperation取出來
將取出的NSOperation封裝的操作放到一條新線程中執(zhí)行
NSOperation的子類
NSOperation是個(gè)抽象類,并不具備封裝操作的能力澜搅,必須使用它的子類
使用NSOperation子類的方式有3種
1.NSInvocationOperation
2.NSBlockOperation
3.自定義子類繼承NSOperation,實(shí)現(xiàn)內(nèi)部相應(yīng)的方法
(也就是寫一個(gè)類繼承自NSOperation,然后去實(shí)現(xiàn)內(nèi)部相對應(yīng)的一些方法)
NSInvocationOperation
創(chuàng)建NSInvocationOperation對象
-(id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;
調(diào)用start方法開始執(zhí)行操作
-(void)start;
一旦執(zhí)行操作上沐,就會(huì)調(diào)用target的sel方法
注意
默認(rèn)情況下,調(diào)用了start方法后并不會(huì)開一條新線程去執(zhí)行操作舵稠,而是在當(dāng)前線程同步執(zhí)行操作
只有將NSOperation放到一個(gè)NSOperationQueue中词渤,才會(huì)異步執(zhí)行操作
NSBlockOperation
創(chuàng)建NSBlockOperation對象
+(id)blockOperationWithBlock:(void (^)(void))block;
通過addExecutionBlock:方法添加更多的操作
-(void)addExecutionBlock:(void (^)(void))block;
注意:只要NSBlockOperation封裝的操作數(shù) > 1,就會(huì)異步執(zhí)行操作
NSOperationQueue
NSOperationQueue的作用
NSOperation可以調(diào)用start方法來執(zhí)行任務(wù)瓷翻,但默認(rèn)是同步執(zhí)行的
如果將NSOperation添加到NSOperationQueue(操作隊(duì)列)中,系統(tǒng)會(huì)自動(dòng)異步執(zhí)行NSOperationQueue中的操作
添加操作到NSOperationQueue中
-(void)addOperation:(NSOperation *)op;
- (void)addOperationWithBlock:(void (^)(void))block;
最大并發(fā)數(shù)
什么是并發(fā)數(shù)
同時(shí)執(zhí)行的任務(wù)數(shù)
比如割坠,同時(shí)開3個(gè)線程執(zhí)行3個(gè)任務(wù)齐帚,并發(fā)數(shù)就是3
最大并發(fā)數(shù)的相關(guān)方法
-(NSInteger)maxConcurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
隊(duì)列的取消、暫停彼哼、恢復(fù)
取消隊(duì)列的所有操作
-(void)cancelAllOperations;
提示:也可以調(diào)用NSOperation的- (void)cancel方法取消單個(gè)操作(在內(nèi)存中給刪除了)
暫停和恢復(fù)隊(duì)列
(void)setSuspended:(BOOL)b; YES代表暫停隊(duì)列对妄,再設(shè)置為NO代表恢復(fù)之前的隊(duì)列
(BOOL)isSuspended;
操作優(yōu)先級(jí)
設(shè)置NSOperation在queue中的優(yōu)先級(jí),可以改變操作的執(zhí)行優(yōu)先級(jí)
- (NSOperationQueuePriority)queuePriority;
-(void)setQueuePriority:(NSOperationQueuePriority)p;
優(yōu)先級(jí)的取值
NSOperationQueuePriorityVeryLow = -8L,
NSOperationQueuePriorityLow = -4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8
操作的監(jiān)聽
可以監(jiān)聽一個(gè)操作的執(zhí)行完畢
(void (^)(void))completionBlock;
(void)setCompletionBlock:(void (^)(void))block;
自定義NSOperation
自定義NSOperation的步驟很簡單
重寫- (void)main方法敢朱,在里面實(shí)現(xiàn)想執(zhí)行的任務(wù)
重寫- (void)main方法的注意點(diǎn)
自己創(chuàng)建自動(dòng)釋放池(因?yàn)槿绻钱惒讲僮骷袅猓瑹o法訪問主線程的自動(dòng)釋放池)
經(jīng)常通過- (BOOL)isCancelled方法檢測操作是否被取消,對取消做出響應(yīng)
SDWebImage
什么是SDWebImage
iOS中著名的牛逼的網(wǎng)絡(luò)圖片處理框架
包含的功能:圖片下載蔫饰、圖片緩存琅豆、下載進(jìn)度監(jiān)聽愉豺、gif處理等等
用法極其簡單篓吁,功能十分強(qiáng)大,大大提高了網(wǎng)絡(luò)圖片的處理效率
國內(nèi)超過90%的iOS項(xiàng)目都有它的影子
面試題:(默認(rèn)的緩沖時(shí)長是多久?
答案為一個(gè)星期)
項(xiàng)目地址
https://github.com/rs/SDWebImage
可能面試的問題:
SDWebImage底層是如何實(shí)現(xiàn)的?(就是這幅圖的思想)
(有時(shí)網(wǎng)速慢了才能察覺到問題的所在,比如說圖片下載失敗,那么就需要設(shè)置一個(gè)占位圖片去填充,還有就是要注意這個(gè)內(nèi)存的問題以上圖片的思想必須記住)
***************************筆記****************************
NSOperation
- NSOperation基本使用
(1)相關(guān)概念
01 NSOperation是對GCD的包裝
02 兩個(gè)核心概念【隊(duì)列+操作】
(2)基本使用
01 NSOperation本身是抽象類蚪拦,只能只有它的子類
02 三個(gè)子類分別是:NSBlockOperation杖剪、NSInvocationOperation以及自定義繼承自NSOperation的類
03 NSOperation和NSOperationQueue結(jié)合使用實(shí)現(xiàn)多線程并發(fā)
(3)相關(guān)代碼
01 NSInvocationOperation (只有將其放入隊(duì)列當(dāng)中,才會(huì)異步執(zhí)行,沒有多大的實(shí)用價(jià)值)
1.封裝操作
第一個(gè)參數(shù):目標(biāo)對象
第二個(gè)參數(shù):該操作要調(diào)用的方法冻押,最多接受一個(gè)參數(shù)
第三個(gè)參數(shù):調(diào)用方法傳遞的參數(shù),如果方法不接受參數(shù)盛嘿,那么該值傳nil
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self selector:@selector(run) object:nil];
2.啟動(dòng)操作
[operation start];
1.封裝操作
NSBlockOperation提供了一個(gè)類方法洛巢,在該類方法中封裝操作
任務(wù)數(shù)量 > 1 才會(huì)異步執(zhí)行
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
在主線程中執(zhí)行
NSLog(@"---download1--%@",[NSThread currentThread]);
}];
2.追加操作,追加的操作在子線程中執(zhí)行
[operation addExecutionBlock:^{
NSLog(@"---download2--%@",[NSThread currentThread]);
}];
[operation addExecutionBlock:^{
NSLog(@"---download3--%@",[NSThread currentThread]);
}];
3.啟動(dòng)執(zhí)行操作
[operation start];
03 自定義NSOperation
如何封裝操作次兆?
自定義的NSOperation,通過重寫內(nèi)部的main方法實(shí)現(xiàn)封裝操作
-(void)main
{
NSLog(@"--main--%@",[NSThread currentThread]);
}
如何使用稿茉?
1.實(shí)例化一個(gè)自定義操作對象
XMGOperation *op = [[XMGOperation alloc]init];
2.執(zhí)行操作
[op start];
- 2.2 NSOperationQueue基本使用
(1)NSOperation中的兩種隊(duì)列
01 主隊(duì)列 通過mainQueue獲得,凡是放到主隊(duì)列中的任務(wù)都將在主線程執(zhí)行
02 非主隊(duì)列 直接alloc init出來的隊(duì)列芥炭。非主隊(duì)列同時(shí)具備了并發(fā)和串行的功能漓库,通過設(shè)置最大并發(fā)數(shù)屬性來控制任務(wù)是并發(fā)執(zhí)行還是串行執(zhí)行
(2)相關(guān)代碼
自定義NSOperation
-(void)customOperation
{
1.創(chuàng)建隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
2.封裝操作
好處:1.信息隱蔽
2.代碼復(fù)用
XMGOperation *op1 = [[XMGOperation alloc]init];
XMGOperation *op2 = [[XMGOperation alloc]init];
3.添加操作到隊(duì)列中
[queue addOperation:op1];
[queue addOperation:op2];
}
NSBlockOperation
-
(void)block
{
1.創(chuàng)建隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];2.封裝操作
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1----%@",[NSThread currentThread]);
}];NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"2----%@",[NSThread currentThread]);}];
[op1 addExecutionBlock:^{
NSLog(@"3----%@",[NSThread currentThread]);
}];[op2 addExecutionBlock:^{
NSLog(@"4----%@",[NSThread currentThread]);
}];3.添加操作到隊(duì)列中
[queue addOperation:op1];
[queue addOperation:op2];補(bǔ)充:簡便方法
[queue addOperationWithBlock:^{
NSLog(@"5----%@",[NSThread currentThread]);
}];
}
NSInvocationOperation
-
(void)invocation
{GCD中的隊(duì)列:
串行隊(duì)列:自己創(chuàng)建的,主隊(duì)列
并發(fā)隊(duì)列:自己創(chuàng)建的园蝠,全局并發(fā)隊(duì)列NSOperationQueue
主隊(duì)列:[NSOperationQueue mainqueue];凡事放在主隊(duì)列中的操作都在主線程中執(zhí)行
非主隊(duì)列:[[NSOperationQueue alloc]init]渺蒿,并發(fā)和串行,默認(rèn)是并發(fā)執(zhí)行的
1.創(chuàng)建隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
2.封裝操作
NSInvocationOperation *op1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download1) object:nil];
NSInvocationOperation *op2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download2) object:nil];
NSInvocationOperation *op3 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download3) object:nil];
3.把封裝好的操作添加到隊(duì)列中
[queue addOperation:op1]; 底層會(huì)調(diào)用->[op1 start]
[queue addOperation:op2];
[queue addOperation:op3];
}
- 2.3 NSOperation其它用法
(1)設(shè)置最大并發(fā)數(shù)【控制任務(wù)并發(fā)和串行】
1.創(chuàng)建隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
2.設(shè)置最大并發(fā)數(shù)
注意點(diǎn):該屬性需要在任務(wù)添加到隊(duì)列中之前進(jìn)行設(shè)置
該屬性控制隊(duì)列是串行執(zhí)行還是并發(fā)執(zhí)行
如果最大并發(fā)數(shù)等于1彪薛,那么該隊(duì)列是串行的茂装,如果大于1那么是并行的
系統(tǒng)的最大并發(fā)數(shù)有個(gè)默認(rèn)的值,為-1善延,如果該屬性設(shè)置為0少态,那么不會(huì)執(zhí)行任何任務(wù)
queue.maxConcurrentOperationCount = 2;
(2)暫停和恢復(fù)以及取消
設(shè)置暫停和恢復(fù)
suspended設(shè)置為YES表示暫停,suspended設(shè)置為NO表示恢復(fù)
暫停表示不繼續(xù)執(zhí)行隊(duì)列中的下一個(gè)任務(wù)易遣,暫停操作是可以恢復(fù)的
if (self.queue.isSuspended) {
self.queue.suspended = NO;
}else
{
self.queue.suspended = YES;
}
取消隊(duì)列里面的所有操作
取消之后况增,當(dāng)前正在執(zhí)行的操作的下一個(gè)操作將不再執(zhí)行,而且永遠(yuǎn)都不在執(zhí)行训挡,就像后面的所有任務(wù)都從隊(duì)列里面移除了一樣
取消操作是不可以恢復(fù)的
[self.queue cancelAllOperations];
---------自定義NSOperation取消操作---------
-(void)main
{
耗時(shí)操作1
for (int i = 0; i<1000; i++) {
NSLog(@"任務(wù)1-%d--%@",i,[NSThread currentThread]);
}
NSLog(@"+++++++++++++++++++++++++++++++++");
蘋果官方建議澳骤,每當(dāng)執(zhí)行完一次耗時(shí)操作之后,就查看一下當(dāng)前隊(duì)列是否為取消狀態(tài)澜薄,如果是为肮,那么就直接退出
好處是可以提高程序的性能
if (self.isCancelled) {
return;
}
耗時(shí)操作2
for (int i = 0; i<1000; i++) {
NSLog(@"任務(wù)1-%d--%@",i,[NSThread currentThread]);
}
NSLog(@"+++++++++++++++++++++++++++++++++");
}
- 2.4 NSOperation實(shí)現(xiàn)線程間通信
(1)開子線程下載圖片
1.創(chuàng)建隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
2.使用簡便方法封裝操作并添加到隊(duì)列中
[queue addOperationWithBlock:^{
3.在該block中下載圖片
NSURL *url = [NSURL URLWithString:@"http://news.51sheyuan.com/uploads/allimg/111001/133442IB-2.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
NSLog(@"下載圖片操作--%@",[NSThread currentThread]);
4.回到主線程刷新UI
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.imageView.image = image;
NSLog(@"刷新UI操作---%@",[NSThread currentThread]);
}];
}];
(2)下載多張圖片合成綜合案例(設(shè)置操作依賴)
02 綜合案例
-
(void)download2
{
NSLog(@"----");
1.創(chuàng)建隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];2.封裝操作下載圖片1
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{NSURL *url = [NSURL URLWithString:@"http://h.hiphotos.baidu.com/zhidao/pic/item/6a63f6246b600c3320b14bb3184c510fd8f9a185.jpg"]; NSData *data = [NSData dataWithContentsOfURL:url]; 拿到圖片數(shù)據(jù) self.image1 = [UIImage imageWithData:data];
}];
3.封裝操作下載圖片2
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSURL *url = [NSURL URLWithString:@"http://pic.58pic.com/58pic/13/87/82/27Q58PICYje_1024.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
拿到圖片數(shù)據(jù)
self.image2 = [UIImage imageWithData:data];
}];
4.合成圖片
NSBlockOperation *combine = [NSBlockOperation blockOperationWithBlock:^{
4.1 開啟圖形上下文
UIGraphicsBeginImageContext(CGSizeMake(200, 200));
4.2 畫image1
[self.image1 drawInRect:CGRectMake(0, 0, 200, 100)];
4.3 畫image2
[self.image2 drawInRect:CGRectMake(0, 100, 200, 100)];
4.4 根據(jù)圖形上下文拿到圖片數(shù)據(jù)
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
4.5 關(guān)閉圖形上下文
UIGraphicsEndImageContext();
7.回到主線程刷新UI
[[NSOperationQueue mainQueue]addOperationWithBlock:^{
self.imageView.image = image;
NSLog(@"刷新UI---%@",[NSThread currentThread]);
}];
}];
5.設(shè)置操作依賴
[combine addDependency:op1];
[combine addDependency:op2];
6.添加操作到隊(duì)列中執(zhí)行
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:combine];
}
3.多圖下載綜合示例程序
(1)涉及知識(shí)點(diǎn)
01 字典轉(zhuǎn)模型
02 存儲(chǔ)數(shù)據(jù)到沙盒,從沙盒中加載數(shù)據(jù)
03 占位圖片的設(shè)置(cell的刷新問題)
04 如何進(jìn)行內(nèi)存緩存(使用NSDictionary)
05 在程序開發(fā)過程中的一些容易出錯(cuò)的問題處理
06 如何刷新tableView的指定行(解決數(shù)據(jù)錯(cuò)亂問題)
07 NSOperation以及線程間通信相關(guān)知識(shí)
4.第三方框架
(1)SDWebImage基本使用
01 設(shè)置imageView的圖片
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:app.icon] placeholderImage:[UIImage imageNamed:@"placehoder"]];
02 設(shè)置圖片并計(jì)算下載進(jìn)度
下載并設(shè)置圖片
第一個(gè)參數(shù):要下載圖片的url地址
第二個(gè)參數(shù):設(shè)置該imageView的占位圖片
第三個(gè)參數(shù):傳一個(gè)枚舉值肤京,告訴程序你下載圖片的策略是什么
第一個(gè)block塊:獲取當(dāng)前圖片數(shù)據(jù)的下載進(jìn)度
receivedSize:已經(jīng)下載完成的數(shù)據(jù)大小
expectedSize:該文件的數(shù)據(jù)總大小
第二個(gè)block塊:當(dāng)圖片下載完成之后執(zhí)行該block中的代碼
image:下載得到的圖片數(shù)據(jù)
error:下載出現(xiàn)的錯(cuò)誤信息
SDImageCacheType:圖片的緩存策略(不緩存颊艳,內(nèi)存緩存,沙盒緩存)
imageURL:下載的圖片的url地址
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:app.icon] placeholderImage:[UIImage imageNamed:@"placehoder"] options:SDWebImageRetryFailed progress:^(NSInteger receivedSize, NSInteger expectedSize) {
計(jì)算當(dāng)前圖片的下載進(jìn)度
NSLog(@"%.2f",1.0 *receivedSize / expectedSize);
} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
}];
03 系統(tǒng)內(nèi)存警告如何處理(面試)
取消當(dāng)前正在進(jìn)行的所有下載操作
[[SDWebImageManager sharedManager] cancelAll];
清除緩存數(shù)據(jù)(面試)注意它們之間的區(qū)別
cleanDisk:刪除過期的文件數(shù)據(jù)忘分,計(jì)算當(dāng)前未過期的已經(jīng)下載的文件數(shù)據(jù)的大小棋枕,如果發(fā)現(xiàn)該數(shù)據(jù)大小大于我們設(shè)置的最大緩存數(shù)據(jù)大小,那么程序內(nèi)部會(huì)按照按文件數(shù)據(jù)緩存的時(shí)間從遠(yuǎn)到近刪除妒峦,知道小于最大緩存數(shù)據(jù)為止重斑。
clearMemory:直接刪除文件,重新創(chuàng)建新的文件夾
[[SDWebImageManager sharedManager].imageCache cleanDisk];
[[SDWebImageManager sharedManager].imageCache clearMemory];
04 SDWebImage默認(rèn)的緩存時(shí)間是1周
05 如何播放gif圖片
5-1 把用戶傳入的gif圖片->NSData
5-2 根據(jù)該Data創(chuàng)建一個(gè)圖片數(shù)據(jù)源(NSData->CFImageSourceRef)
5-3 計(jì)算該數(shù)據(jù)源中一共有多少幀肯骇,把每一幀數(shù)據(jù)取出來放到圖片數(shù)組中
5-4 根據(jù)得到的數(shù)組+計(jì)算的動(dòng)畫時(shí)間-》可動(dòng)畫的image
[UIImage animatedImageWithImages:images duration:duration];
06 如何判斷當(dāng)前圖片類型
- (NSString *)sd_contentTypeForImageData:(NSData *)data;
(2)SDWebImage內(nèi)部結(jié)構(gòu)
Cocoapods的安裝
1.先升級(jí)Gem
sudo gem update --system
2.切換cocoapods的數(shù)據(jù)源
【先刪除窥浪,再添加祖很,查看】
gem sources --remove https://rubygems.org/
gem sources -a https://ruby.taobao.org/
gem sources -l
3.安裝cocoapods
sudo gem install cocoapods
4.將Podspec文件托管地址從github切換到國內(nèi)的oschina
【先刪除,再添加漾脂,再更新】
pod repo remove master
pod repo add master http://git.oschina.net/akuandev/Specs.git
pod repo add master https://gitcafe.com/akuandev/Specs.git
pod repo update
5.設(shè)置pod倉庫
pod setup
6.測試
【如果有版本號(hào)假颇,則說明已經(jīng)安裝成功】
pod --version
7.利用cocoapods來安裝第三方框架
01 進(jìn)入要安裝框架的項(xiàng)目的.xcodeproj同級(jí)文件夾
02 在該文件夾中新建一個(gè)文件podfile
03 在文件中告訴cocoapods需要安裝的框架信息
a.該框架支持的平臺(tái)
b.適用的iOS版本
c.框架的名稱
d.框架的版本
8.安裝
pod install --no-repo-update
pod update --no-repo-update