为什么我的完成块是用NSOperation对象触发的

时间:2012-11-14 00:05:15

标签: iphone objective-c concurrency nsoperation nsoperationqueue

我有一个NSOperation自定义类,我在其中添加了一个方法来接受块的简易性,以便我可以分配完成块。但是,即使我不调用该块,它也会被返回到主调用类并发送消息并传递给它自己。

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

我如何调用该操作;

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);
}

正如您在上面的代码中所看到的,我在connectionDidFinishLoading:方法中取消注释了对block的调用,但是正在调用该块,并且正在触发方法populateReceivedJSON。

对我来说更有趣的是log显示了与NSOperation子类相同的实例; 的 JSON --> <SKSimpleDownloadOperation: 0x7462be0>

我无法理解这里的问题是什么?当我调用delegate时它工作正常,但块总是被调用。我想提前感谢您的热情建议和想法。

1 个答案:

答案 0 :(得分:4)

NSOperation Class Reference

  

<强> completionBlock
  返回操作主要任务完成时要执行的块。

     

- (void(^)(void))completionBlock
    返回值
  操作主要任务完成后执行的块。这个块没有   参数并没有返回值。

     

讨论当isFinished方法返回的值更改为YES时,将执行您提供的完成块。因此,这个   在操作之后,操作对象执行块   主要任务已完成或取消

如果您将操作放在队列上,则操作完成或取消时将调用完成块 此外,您的“自定义”完成块可能会干扰NSOperation的“completionBlock” I would suggest using a different name for your custom completionBlock,因为它不是您想要的NSOperation completionBlock的行为,而是其他内容。