When dealing with the network, we often encounter the situation that the network requests depend on each other. For example, the parameter of B request depends on the callback result of A request. If B is requested directly in the callback of A request, it will lead to the nesting of callbacks, which leads to the tight coupling between requests. Here's an elegant way to take advantage of the operation dependency of NSOperation.
- This example attempts to download two pictures, assuming that picture 2 is always displayed after picture 1.
- Download framework AFNetworking3
To use the operation dependency of NSOperation, an NSOperationQueue is required first:
NSOperationQueue *queue = [[NSOperationQueue alloc] init]; queue.name = @"SessionQueue";
Because the AFHTTPSessionManager in AFNetworking3 is not a subclass of NSOperation, which is very different from AFNetworking2. It can't be directly added to NSOperationQueue. It needs to be encapsulated. Fortunately, a third-party library has done all the work. First, it is introduced to the Library:
pod 'AFSessionOperation', :git => 'https://github.com/robertmryan/AFHTTPSessionOperation.git'
AFHTTPSessionOperation is a subclass of NSOperation. At the same time, AFNetworking is called to implement HTTP request. The following is the implementation of request operation:
NSString *imangeUrl1 = @"https://upload-images.jianshu.io/upload_images/2025746-368aa3a508d2fbac.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"; NSString *imangeUrl2 = @"https://upload-images.jianshu.io/upload_images/2025746-27bbf45bea40162c.JPEG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"; NSOperation *op1 = [AFHTTPSessionOperation operationWithManager:manager HTTPMethod:@"GET" URLString:imangeUrl1 parameters:nil uploadProgress:nil downloadProgress:nil success:^(NSURLSessionDataTask *task, id responseObject) { NSLog(@"finished 1"); UIImage *image = [UIImage imageWithData:responseObject]; _imageView1.image = image; } failure:^(NSURLSessionDataTask *task, NSError *error) { NSLog(@"failed 1 - error = %@", error.localizedDescription); }]; NSOperation *op2 = [AFHTTPSessionOperation operationWithManager:manager HTTPMethod:@"GET" URLString:imangeUrl2 parameters:nil uploadProgress:nil downloadProgress:nil success:^(NSURLSessionDataTask *task, id responseObject) { NSLog(@"finished 2"); UIImage *image = [UIImage imageWithData:responseObject]; _imageView2.image = image; } failure:^(NSURLSessionDataTask *task, NSError *error) { NSLog(@"failed 2 - error = %@", error.localizedDescription); }];
op2 depends on op1:
[op2 addDependency:op1];
Finally, add op1 and op2 to the operation queue, which will start executing the network request:
[queue addOperations:@[op1, op2] waitUntilFinished:false];
Execution result:
According to our design, op2 is executed after op1 is completed.
When using, be careful not to create a dependency ring, such as this:
[op1 addDependency:op2]; [op2 addDependency:op1];
Neither operation will be performed.