NSOperation的作用:
配合使用NSOperation和NSOperationQueue能實(shí)現(xiàn)多線程編程.
NSOperation和NSOperationQueue能實(shí)現(xiàn)多線程的具體步驟
1.首先需要將執(zhí)行的操作封裝到一個(gè)NSOperation對(duì)象中(我們稱之為 任務(wù))
2.然后將NSOperation對(duì)象加到NSOperationQueue中
3.系統(tǒng)會(huì)自動(dòng)將NSOperationQueue中的NSOperation取出來(lái)
4.將取出的NSOperation封裝的操作放在一條新線程
中執(zhí)行
NSOperation的子類
1.NSOperation是一個(gè)抽象類,不具備封裝操作的能力,必須使用它的子類
2.使用NSOperation子類的方式有3種
1>NSInvocationOperation
2>NSBlockOperation
自定義子類繼承NSOperation,實(shí)現(xiàn)內(nèi)部相應(yīng)的方法
雖然NSOperation較GCD比較而言,有點(diǎn)繁瑣,但是它能夠自由的控制任務(wù)的執(zhí)行,而且經(jīng)過(guò)測(cè)試,它的穩(wěn)定性比較高.
好了現(xiàn)在介紹:自定義NSOperation的方式來(lái)添加任務(wù)
自定義類,繼承于NSOperation
// NSOperation內(nèi)部有這個(gè)方法, 是用來(lái)專門(mén),封裝任務(wù)體的
// 默認(rèn)情況下如果直接調(diào)用start的時(shí)候,不會(huì)新開(kāi)一條新線程去執(zhí)行操作
- (void)main
{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"我愛(ài)你 ------ %@", [NSThread currentThread]);
}
利用NSInvocationOperation來(lái)添加任務(wù)
1.創(chuàng)建NSInvocationOperation對(duì)象
NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(run:) object:@"我愛(ài)你"];
2.調(diào)用start方法開(kāi)始執(zhí)行操作
- (void)start
一點(diǎn)執(zhí)行這個(gè)操作,就會(huì)調(diào)用target的sel的方法
3.注意
1>默認(rèn)情況下,調(diào)用了start方法后并不會(huì)開(kāi)一條新線程去執(zhí)行操作,而是在當(dāng)前線程同步執(zhí)行操作
2>只有將NSOperation放在一個(gè)NSOperationQueue中,才會(huì)異步執(zhí)行操作
利用NSBlockOperation來(lái)添加任務(wù)
1.創(chuàng)建NSBlockOperation對(duì)象
2.通過(guò)addExecutionBlock:方法添加更多的操作
3.注意:只要NSBlockOperation封裝的操作數(shù) > 1,就會(huì)異步執(zhí)行操作
// block 直接將 操作封裝在 block中 ,執(zhí)行的毛嫉。 會(huì)進(jìn)行并行操作裳仆,并且第一條操作 安排在主線程。 不必指定 target
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"?(′???`?)----%@",[NSThread currentThread]);
}];
[operation addExecutionBlock:^{
NSLog(@"我愛(ài)你----%@",[NSThread currentThread]);;
}];
[operation addExecutionBlock:^{
NSLog(@"我愛(ài)你----%@",[NSThread currentThread]);;
}];
[operation addExecutionBlock:^{
NSLog(@"我愛(ài)你----%@",[NSThread currentThread]);;
}];
// 調(diào)用 start 統(tǒng)一開(kāi)始執(zhí)行任務(wù)
[operation start];
控制臺(tái)輸出:
NSOperationQueue
NSOperationQueue的作用
1.NSOperation可以調(diào)用start方法來(lái)執(zhí)行任務(wù),但默認(rèn)是同步執(zhí)行的
2.如果將NSOperation添加到NSOperationQueue(操作隊(duì)列)中,系統(tǒng)會(huì)自動(dòng)異步執(zhí)行NSOperation中的操作
添加操作(任務(wù))到NSOperationQueue中 (需要注意的是,一旦加入隊(duì)列,任務(wù)就會(huì)被執(zhí)行.)
1.添加任務(wù)對(duì)象到隊(duì)列中
- (void)addOperation:(NSOperation *)op
2.添加任務(wù)'block'到隊(duì)列,直接執(zhí)行
- (void)addOperationWithBlock:(void (^)(void))block
// 創(chuàng)建隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//
__block UIImage *image1;
NSBlockOperation *block1 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:2.0];
NSURL *url = [NSURL URLWithString:@"http://fc.topit.me/c/4f/99/11922014783d4994fco.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
image1 = [UIImage imageWithData:data];
NSLog(@"1------%@",[NSThread currentThread]);
}];
__block UIImage *image2;
NSBlockOperation *block2 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:2.0];
NSURL *url = [NSURL URLWithString:@"http://cdn.duitang.com/uploads/item/201311/25/20131125164036_NUAC8.jpeg"];
NSData *data = [NSData dataWithContentsOfURL:url];
image2 = [UIImage imageWithData:data];
NSLog(@"2------%@",[NSThread currentThread]);
}];
NSBlockOperation *block3 = [NSBlockOperation blockOperationWithBlock:^{
UIGraphicsBeginImageContext(CGSizeMake(200, 200));
[image1 drawInRect:CGRectMake(0, 50, 200, 150)];
[image2 drawInRect:CGRectMake(0, 0, 200, 50)];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// 回到主隊(duì)列 裹纳, 進(jìn)行UI賦值
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.imageView.image = image;
}];
}];
// addDependency 添加依賴 , 前倆個(gè) 紧武,執(zhí)行完了之后 最后一個(gè)再執(zhí)行剃氧。
[block3 addDependency:block1];
[block3 addDependency:block2];
[queue addOperation:block1];
[queue addOperation:block2];
[ queue addOperation:block3 ];
// // 先讓執(zhí)行 block1, block2 (異步并發(fā)執(zhí)行) 阻星,在進(jìn)行 block3 的執(zhí)行
// [queue addOperations:@[block1,block2] waitUntilFinished:YES];
// [queue addOperation:block3];
//
幾種常見(jiàn)的屬性和方法
1.最大并發(fā)數(shù)(同時(shí)執(zhí)行的任務(wù)數(shù)) 最大并發(fā)數(shù)一般都是系統(tǒng)給出,我任務(wù),系統(tǒng)并發(fā)送是系統(tǒng)根據(jù)它的性能, 給分配的線程,如果性能高,可能多分點(diǎn). 至于并發(fā)送內(nèi)部怎么執(zhí)行 ,系統(tǒng)自行做決定, 它認(rèn)為哪條線程空閑,他就會(huì)把哪條線程交給你
- (NSInteger)maxCurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt
有些人,會(huì)陷入誤區(qū), 如果設(shè)置了最大并發(fā)數(shù)是1,那么系統(tǒng)就只會(huì)創(chuàng)建一條線程, 因?yàn)?同一時(shí)間只允許一條線程執(zhí)行任務(wù), 但是這種想法是錯(cuò)誤的, 系統(tǒng)只是保持同一時(shí)間執(zhí)行任務(wù)是一條線程, 但沒(méi)表示 換個(gè)時(shí)間就不能換線程
// 默認(rèn)不設(shè)置并發(fā)數(shù)的時(shí)候, 異步執(zhí)行, 創(chuàng)建多條線程
let queue = NSOperationQueue()
queue.addOperationWithBlock { () -> Void in
print("1------\(NSThread.currentThread())")
}
queue.addOperationWithBlock { () -> Void in
print("1------\(NSThread.currentThread())")
}
queue.addOperationWithBlock { () -> Void in
print("1------\(NSThread.currentThread())")
}
queue.addOperationWithBlock { () -> Void in
print("1------\(NSThread.currentThread())")
}
queue.addOperationWithBlock { () -> Void in
print("1------\(NSThread.currentThread())")
}
queue.addOperationWithBlock { () -> Void in
print("1------\(NSThread.currentThread())")
}
queue.addOperationWithBlock { () -> Void in
print("1------\(NSThread.currentThread())")
}
queue.addOperationWithBlock { () -> Void in
print("1------\(NSThread.currentThread())")
}
***添加
queue.maxConcurrentOperationCount = 1
可以看出來(lái), 線程并不是一樣的. 所以最大并發(fā)數(shù)的理解, 應(yīng)該是我上面指出的
2.隊(duì)列的取消,暫停,和恢復(fù)
1>取消隊(duì)列的所有操作
- (void)cancelAllOpertions
注意: 也可以調(diào)用NSOperation的-(void)cancel方法取消單個(gè)操作. (總感覺(jué)單個(gè)任務(wù)取消不掉)
2>暫停和恢復(fù)隊(duì)列
- (void)setSuspended:(BOOL)b
// YES 代表暫停隊(duì)列,NO代表恢復(fù)隊(duì)列
- (BOOL)isSuspended
操作依賴
首先依賴其他的線程中也有說(shuō)過(guò) GCD ----<barrier, group都是依賴的意思>
NSOperation之間可以設(shè)置依賴來(lái)保證執(zhí)行順序.
操作之間添加依賴
[operationB addDependency:operationA]
操作B依賴于A
不同隊(duì)列之間也可以進(jìn)行任務(wù)的依賴, 但是需要注意的是, 不要相互依賴