Reputation: 21154
I have an NSOperation custom class in which I added a method to accept block for easiness such that I could assign the completion block. But, even if I dont call the block, it is being returned to the main calling class and sends message with itself being passed.
Interface :
@class SKSimpleDownloadOperation;
typedef void(^CompletionBlock)(id Json, NSError *error);
@protocol SKSimpleDownloadDelegate <NSObject>
-(void)operation:(SKSimpleDownloadOperation*)operation didCompleteWithData:(NSData*)data;
-(void)operation:(SKSimpleDownloadOperation*)operation didFailWithError:(NSError*)error;
@end
@interface SKSimpleDownloadOperation : NSOperation
@property(nonatomic, assign) NSInteger statusCode;
-(id)initWithUrlRequest:(NSURLRequest*)request andDelegate:(id<SKSimpleDownloadDelegate>)aDelegate;
-(id)initWithUrlRequest:(NSURLRequest*)request andDelegate:(id<SKSimpleDownloadDelegate>)aDelegate withCompletionBlock:(void(^)(id json, NSError *error))completionBlock;
@end
Implementation:
@interface SKSimpleDownloadOperation()<NSURLConnectionDataDelegate>
@property(nonatomic, strong) NSURLRequest *request;
@property(nonatomic, strong) NSMutableData *data;
@property(nonatomic, assign) id<SKSimpleDownloadDelegate>delegate;
@property(nonatomic, copy) CompletionBlock completionBlock;
@end
@implementation SKSimpleDownloadOperation
@synthesize delegate;
@synthesize request;
@synthesize statusCode;
@synthesize completionBlock;
-(id)initWithUrlRequest:(NSURLRequest *)aRequest andDelegate:(id<SKSimpleDownloadDelegate>)aDelegate withCompletionBlock:(void (^)(id, NSError *))aCompletionBlock{
if(!(self = [super init])) return nil;
[self setRequest:aRequest];
[self setDelegate:aDelegate];
[self setCompletionBlock:aCompletionBlock];
return self;
}
-(id)initWithUrlRequest:(NSURLRequest *)aRequest andDelegate:(id<SKSimpleDownloadDelegate>)aDelegate{
return [self initWithUrlRequest:aRequest andDelegate:aDelegate withCompletionBlock:nil];
}
-(void)main{
[NSURLConnection connectionWithRequest:[self request] delegate:self];
CFRunLoopRun();
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response{
[self setStatusCode:[response statusCode]];
[self setData:[NSMutableData data]];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)newData{
[[self data] appendData:newData];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
if(self.delegate && [self.delegate respondsToSelector:@selector(operation:didCompleteWithData:)])
[[self delegate] operation:self didCompleteWithData:[self data]];
CFRunLoopStop(CFRunLoopGetCurrent());
// if(completionBlock != nil){
// [self performSelector:@selector(callBlockWithNecessaryParameter) onThread:[NSThread mainThread] withObject:nil waitUntilDone:NO];
// }
}
-(void)callBlockWithNecessaryParameter{
NSError *error = nil;
id object = [NSJSONSerialization JSONObjectWithData:[self data] options:NSJSONReadingAllowFragments error:&error];
// completionBlock(object,error);
//completionBlock = nil;
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
[[self delegate] operation:self didFailWithError:error];
CFRunLoopStop(CFRunLoopGetCurrent());
}
@end
How I call the operation;
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://query.yahooapis.com/v1/public/yql?q=select%20item%20from%20weather.forecast%20where%20location%3D%2248907%22&format=json"]];
ViewController __weak *__viewController = self;
NSOperation *operation = [[SKSimpleDownloadOperation alloc] initWithUrlRequest:request andDelegate:nil withCompletionBlock:^(id json, NSError *error) {
[__viewController populateReceivedJSON:json];
}];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
operation = nil;
queue = nil;
-(void)populateReceivedJSON:(id)json{
NSLog(@"JSON --> %@", json);
}
As you see in the above code I uncommented the call to block in connectionDidFinishLoading: method but the block is being called and the method populateReceivedJSON is being triggered.
And more interesting to me is log shows the same instance of NSOperation subclass as;
JSON --> <SKSimpleDownloadOperation: 0x7462be0>
I could not understand what is the problem here ? When I call delegate it works fine but the block gets called always. I would like to thankyou in advance for your warm suggestions and ideas.
Upvotes: 1
Views: 2225
Reputation: 8664
completionBlock
Returns the block to execute when the operation’s main task is complete.-(void (^)(void))completionBlock
Return Value
The block to execute after the operation’s main task is completed. This block takes no parameters and has no return value.Discussion The completion block you provide is executed when the value returned by the isFinished method changes to YES. Thus, this block is executed by the operation object after the operation’s primary task is finished or cancelled.
If you place the Operation on a Queue the completion block will be call when the operation is completed or cancelled.
Also your "custom" completion block may be interfering with the "completionBlock" of NSOperation.
I would suggest using a different name for your custom completionBlock,
since it's not the behaviour of the NSOperation completionBlock that you want, but something else.
Upvotes: 4