I have NSOperation with AFHTTPClient request. In end of operation i need to perform another N operations with requests and wait that requests will be finished to mark main operation as finished
@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
Link to OBOperation
source at end of question. It's a simple class that add useful methods to control NSOperation
flow
Sample of Inner Operation:
@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
So if i begin my operation:
MyOperation *op = [MyOperation new];
[_queue addOperation:op];
I see in console begin inner operation: 1
and that's all! My app totally freeze (even UI)
After some exploration i decide that freeze caused by [queue addOperations:ops waitUntilFinished:YES];
. If i don't wait for finish, my inner operations work as expected, but MyOperation finished before child operations will be completed.
So now i have workaround with dependent block operation:
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];
But i still totally don't understand what's real problem of this freeze. Any explanation will be very useful.
OBOperaton class source: https://dl.dropboxusercontent.com/u/1999619/issue/OBOperation.h https://dl.dropboxusercontent.com/u/1999619/issue/OBOperation.m
Whole project: https://dl.dropboxusercontent.com/u/1999619/issue/OperationsTest.zip