1. NSOperation features

1, flexible,

2, freely

How to use NSOperation

1. There are three steps to use NSOperation: create an operation, create a queue, and add an operation to a queue

NSOperation is an abstract class, so we can only use subclasses NSInvocationOperation and NSBlockOperation

1.1, NSInvocationOperation
- (void)demo {// Handle transaction NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(handleInvocation:) object:@"hehe"]; NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [queue addOperation:op]; } ----- print: hehe -- <NSThread: 0x60000393A500 >{number = 7, name = (null)}Copy the code
- (void)demo1_1 { NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(handleInvocation:) object:@"123"]; [op start]; } ------ print: 123 -- <NSThread: 0x600003C90CC0 >{number = 1, name = main}Copy the code
- (void)demo1_2 { NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(handleInvocation:) object:@"123"]; NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [queue addOperation:op]; [op start]; } -- -- -- -- -- print: * * * Terminating app due to uncaught exception 'NSInvalidArgumentException, reason: '*** -[NSInvocationOperation start]: Something is trying to start the receiver simultaneously from more than one thread' ----- reason: Starting the task again in running is confusing, so it is best not to start it directlyCopy the code
- (void)demo1_3 { NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(handleInvocation:) object:@"123"]; [[NSOperationQueue mainQueue] addOperation:op]; } ----- print: 123 -- <NSThread: 0x6000027C4CC0 >{number = 1, name = main}Copy the code
1.2, NSBlockOperation
- (void)demo2 {// Function programming block over target advantage: Block is more precise, //1: create blockOperation -- NSBlockOperation *bo = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"%@",[NSThread currentThread]); sleep(3); }]; [bo addExecutionBlock:^{NSLog(@" this is a block - %@",[NSThread currentThread]);}]; ^{NSLog(@" done!!") = ^{NSLog(@" done!! ); }; NSOperationQueue *queue = [[NSOperationQueue alloc] init]; //3: Add to queue [queue addOperation:bo]; NSLog(@" transaction added to NSOperationQueue"); } ----- print: transaction added to NSOperationQueue <NSThread: 0x600000B4D580 >{number = 4, name = (null)} this is an execution code block - <NSThread: 0x600000B4E180 >{number = 5, name = (null)} Complete!! ----- Cause: NSOperation depends on queue execution and is asynchronous, so the nslog of the main thread is executed first ----- Thought: Why addExecutionBlock- Add task ----- Cause: Compared with GCD, ---- controllability. GCD cannot control (e.g., cancel) this task, but NSOperation can.Copy the code
*/ - (void)demo3 {NSOperationQueue *queue = [[NSOperationQueue alloc] init]; for (int i = 0; i<20; i++) { [queue addOperationWithBlock:^{ NSLog(@"%@---%d",[NSThread currentThread],i); }]; }} ----- print: <NSThread: 0x600001444D80 >{number = 6, name = (null)}-- 0 <NSThread: 0x600001446600>{number = 4, name = (null)}---1 <NSThread: 0x60000147e800>{number = 7, name = (null)}---2 <NSThread: 0x600001446580>{number = 3, name = (null)}---3 <NSThread: 0x600001446600>{number = 4, name = (null)}---4 <NSThread: 0x600001444d80>{number = 6, name = (null)}---5 <NSThread: 0x600001446580>{number = 3, name = (null)}---6 <NSThread: 0x600001446600>{number = 4, name = (null)}---7 <NSThread: 0x600001444d80>{number = 6, name = (null)}---8 <NSThread: 0x60000147e800>{number = 7, name = (null)}---9 <NSThread: 0x600001446580>{number = 3, name = (null)}---10 <NSThread: 0x600001446600>{number = 4, name = (null)}---11 <NSThread: 0x60000147A780 >{number = 8, name = (null)}-- 0x60000147F740 >{number = 10, name = (null)}-- 0x600001477640>{number = 9, name = (null)}-- 0x600001444d80>{number = 6, name = (null)}---15 <NSThread: 0x600001446580>{number = 3, name = (null)}---16 <NSThread: 0x60000147a780>{number = 8, name = (null)}---17 <NSThread: 0x60000147a940>{number = 11, name = (null)}---18 <NSThread: 0x600001477440>{number = 12, name = (null)}---19Copy the code
*/ - (void)demo4 {// Priority NSBlockOperation *bo1 = [NSBlockOperation BlockOperationWithBlock :^{for (int I = 0; I < 5; I ++) {NSLog(@"** first operation ** %d -- %@", I, [NSThread currentThread]); }}]; / / set the highest priority - bo1. QualityOfService = NSQualityOfServiceUserInteractive; NSBlockOperation *bo2 = [NSBlockOperation blockOperationWithBlock:^{for (int I = 0; I < 5; I++) {NSLog (@ "the second operation % d - % @", I, [NSThread currentThread]);}}]; / / set the lowest priority - bo2. QualityOfService = NSQualityOfServiceBackground; NSOperationQueue *queue = [[NSOperationQueue alloc] init]; Queue addOperation:bo2 [queue addOperation:bo2]; [queue addOperation:bo1]; } ----- print: ** first operation ** 0 -- <NSThread: 0x600003EC0940 >{number = 4, name = (null)} ** first operation ** 1 -- <NSThread: 0x600003EC0940 >{number = 4, name = (null)} ** First operation ** 2 -- <NSThread: 0x600003EC0940 >{number = 4, name = (null)} ** First operation ** 3 -- <NSThread: 0x600003EC0940 >{number = 4, name = (null)} ** First operation ** 4 -- <NSThread: 0x600003EC0940 >{number = 4, name = (null)} 0x600003EE8E00 >{number = 7, name = (null)} 0x600003EE8E00 >{number = 7, name = (null)} 0x600003EE8E00 >{number = 7, name = (null)} 0x600003EE8E00 >{number = 7, name = (null)} NSThread: 0x600003EE8E00 >{number = 7, name = (null)}Copy the code
/** thread communication */ - (void)demo5 {NSOperationQueue *queue = [[NSOperationQueue alloc] init]; queue.name = @"hehe"; [queue addOperationWithBlock:^{ NSLog(@"%@ = %@",[NSOperationQueue currentQueue],[NSThread currentThread]); [[NSOperationQueue mainQueue] addOperationWithBlock:^{NSLog(@"%@ --%@",[NSOperationQueue currentQueue],[NSThread currentThread]); }]; }]; } ----- print: <NSOperationQueue: 0x7ffD78f05400 >{name = 'hehe'} = <NSThread: 0x60000305bc00>{number = 5, name = (null)} <NSOperationQueue: 0x7ffd78e01da0>{name = 'NSOperationQueue Main Queue'} --<NSThread: 0x600003014a80>{number = 1, name = main}Copy the code
- (void)demo6 {self.queue. Name = @"hehe"; self.queue.maxConcurrentOperationCount = 2; // self.queue + op for (int i = 0; i<10; I++) {[self.queue addOperationWithBlock:^{// a task [NSThread sleepForTimeInterval:2];  NSLog(@"%d-%@",i,[NSThread currentThread]); }]; }} ----- print: this cannot be demonstrated, the running condition is to print two nslogs every two seconds cause: execute two tasks at a time, wait two seconds for both of them to complete, then execute the last twoCopy the code

2. Set up dependencies — most important

- (void)demo2 { NSBlockOperation *bo1 = [NSBlockOperation blockOperationWithBlock:^{ [NSThread SleepForTimeInterval :0.5]; NSLog(@" request token");}]; NSBlockOperation *bo2 = [NSBlockOperation blockOperationWithBlock:^{[NSThread sleepForTimeInterval:0.5]; NSLog(@" hold token, request data 1");}]; NSBlockOperation *bo3 = [NSBlockOperation blockOperationWithBlock:^{[NSThread sleepForTimeInterval:0.5]; NSLog(@" hold dat1, request dat2 ");}]; // create dependency (bo2 addDependency:bo1); [bo3 addDependency:bo2]; // [bo1 addDependency:bo3]; [self.queue addOperations:@[bo1,bo2,bo3] waitUntilFinished:YES]; NSLog at sign "done? I'll do something else "); } ----- print: Request token holding token, request data 1 holding data 1, request data 2 executed? I have other things to doCopy the code

Suspend operationQueue, continue, cancel

- (void)demo1 { self.queue.name = @"hehe"; self.queue.maxConcurrentOperationCount = 2; for (int i=0; i< 100; I++) {[self.queue addOperationWithBlock:^{[NSThread sleepForTimeInterval:1.0];  NSLog(@"%@-----%d",[NSThread currentThread],i); }]; }} - IBAction pauseOrContinue: (id) sender {the if (self) queue) operationCount = = 0) {NSLog (@ "currently there is no operation, no need to hang and continue"); return; } if (self.queue.suspended) {NSLog(@" currently suspended, ready to continue "); } else {NSLog(@" currently executing, ready to suspend "); } self.queue.suspended = ! self.queue.isSuspended; } - (IBAction)cancel:(id)sender {} - (IBAction)cancel:(id)sender {} - (IBAction)cancel:(id)sender {} - (IBAction)cancel:(id)sender cancelAllOperations]; } ----- print: <NSThread: <NSThread: 0x600000dd1d00>{number = 3, name = (null)}-----1 <NSThread: 0x600000ddd7c0>{number = 4, name = (null)}-----0 <NSThread: 0x600000ddd180>{number = 5, name = (null)}-----2 <NSThread: 0x600000dbc740>{number = 6, name = (null)}-----3 <NSThread: 0x600000ddd7c0>{number = 4, name = (null)}-----4 <NSThread: 0x600000dbc740>{number = 6, name = (null)}-----5 <NSThread: 0x600000ddd180>{number = 5, name = (null)}-----6 <NSThread: 0x600000DBC740 >{Number = 6, name = (null)}-----7 Currently in the execution state and ready to suspend <NSThread: 0x600000dd1d00>{number = 3, name = (null)}-----8 <NSThread: 0x600000DBC740 >{Number = 6, Name = (null)}-----9 ----- Question: Why are two executions performed after suspension? A: Because the two tasks prior to the suspend time have already been scheduled, they will be executed in the thread - already scheduled tasks cannot be suspendedCopy the code

Episode:

Once a task in a queue is scheduled, it leaves the queue and waits for the CPU to schedule threads to execute it. The number of threads generated is independent of the queue. Tasks scheduled for the main queue are executed by the main thread, while tasks for other queues are executed by child threads.

3. Application of NSOperation

1. Imitate a simple SDWebImage

UIImage *cacheImage = self. ImageCacheDict [model.imageurl]; UIImage *cacheImage = self. If (cacheImage) {NSLog(@" get image from memory :%@",model.title); cell.imageView.image = cacheImage; return cell; } // Sandbox cache -- UIImage *diskImage = [UIImage imageWithContentsOfFile:[model.imageurl getDowloadImagePath]]; If (diskImage) {NSLog(@" get image from sandbox :%@",model.title); cell.imageView.image = diskImage; [self.imageCacheDict setValue:diskImage forKey:model.imageUrl]; // Don't forget to cache the return cell; } NSBlockOperation *bo = [NSBlockOperation blockOperationWithBlock:^{ NSLog (@ "to download: % @" model. The title); / / delay NSData * data = [NSData dataWithContentsOfURL: imageURL]; UIImage *image = [UIImage imageWithData:data]; // Save memory [self.imagecachedict setValue:image forKey: model.imageurl];  [data writeToFile:[model.imageUrl getDowloadImagePath] atomically:YES]; // Update UI [[NSOperationQueue mainQueue] addOperationWithBlock:^{cell.imageView.image = image;}];}]; [self.queue addOperation:bo]; return cell;Copy the code