我对AFHTTPClient请求有NSOperation。在操作结束时,我需要对请求执行另外N个操作,并等待请求完成以将主操作标记为已完成
@interface MyOperation : OBOperation
@end
@implementation MyOperation
- (id)init
{
if (self = [super init]) {
self.state = OBOperationReadyState;
}
return self;
}
- (void)start
{
self.state = OBOperationExecutingState;
AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:@"http://google.com"]];
[client getPath:@"/"
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSOperationQueue *queue = [NSOperationQueue new];
queue.maxConcurrentOperationCount = 1;
NSMutableArray *ops = [NSMutableArray array];
for (int i = 1; i < 10; i++) {
MyInnerOperation *innerOp = [[MyInnerOperation alloc] initWithNumber:@(i)];
[ops addObject:innerOp];
}
[queue addOperations:ops waitUntilFinished:YES];
self.state = OBOperationFinishedState;
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
self.state = OBOperationFinishedState;
NSLog(@"error");
}];
}
@end
在问题结尾处链接到OBOperation
来源。这是一个简单的类,它添加了有用的方法来控制NSOperation
流程
内部操作样本:
@interface MyInnerOperation : OBOperation
- (id)initWithNumber:(NSNumber *)number;
@end
@implementation MyInnerOperation
- (id)initWithNumber:(NSNumber *)number
{
if (self = [super init]) {
_number = number;
self.state = OBOperationReadyState;
}
return self;
}
- (void)start
{
self.state = OBOperationExecutingState;
NSLog(@"begin inner operation: %@", _number);
AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:@"http://google.com"]];
[client getPath:@"/"
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"inner operation success: %@", _number);
self.state = OBOperationFinishedState;
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
self.state = OBOperationFinishedState;
NSLog(@"inner operation error: %@", _number);
}];
}
@end
所以,如果我开始操作:
MyOperation *op = [MyOperation new];
[_queue addOperation:op];
我在控制台begin inner operation: 1
中看到了这一切!我的应用程序完全冻结(甚至UI)
经过一番探索后,我决定由[queue addOperations:ops waitUntilFinished:YES];
造成冻结。如果我不等待完成,我的内部操作按预期工作,但MyOperation在子操作完成之前完成。
所以现在我有依赖块操作的解决方法:
NSBlockOperation *endOperation = [NSBlockOperation blockOperationWithBlock:^{
self.state = OBOperationFinishedState;
}];
NSMutableArray *ops = [NSMutableArray arrayWithObject:endOperation];
for (int i = 1; i < 10; i++) {
MyInnerOperation *innerOp = [[MyInnerOperation alloc] initWithNumber:@(i)];
[ops addObject:innerOp];
[endOperation addDependency:innerOp];
}
[queue addOperations:ops waitUntilFinished:NO];
但我仍然完全不明白这个冻结的真正问题是什么。任何解释都非常有用。
OBOperaton类来源:https://dl.dropboxusercontent.com/u/1999619/issue/OBOperation.h https://dl.dropboxusercontent.com/u/1999619/issue/OBOperation.m
整个项目:https://dl.dropboxusercontent.com/u/1999619/issue/OperationsTest.zip
答案 0 :(得分:3)
您遇到死锁的原因是AFNetworking将完成块调度到主队列。因此,第一个waitUntilFinished
处理程序中的success
将阻止主队列,直到下级请求完成。但是那些从属请求无法完成,因为他们需要将完成块分配给主队列,第一个操作仍在阻塞。
显然,你永远不想阻塞主队列,但是如果你阻塞等待操作的主队列就会收到死锁,这些操作本身就需要主队列。