【问题标题】:Why is my completion block being triggered with NSOperation object为什么我的完成块被 NSOperation 对象触发
【发布时间】:2012-11-14 00:05:14
【问题描述】:

我有一个 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: 方法中对块的调用的注释,但是正在调用块并且正在触发 populateReceivedJSON 方法。

对我来说更有趣的是日志显示了与 NSOperation 子类相同的实例; JSON --&gt; &lt;SKSimpleDownloadOperation: 0x7462be0&gt;

我不明白这里有什么问题?当我调用委托时,它工作正常,但块总是被调用。提前感谢您的热情建议和想法。

【问题讨论】:

    标签: iphone objective-c concurrency nsoperation nsoperationqueue


    【解决方案1】:

    NSOperation Class Reference

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

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

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

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

    【讨论】:

    • 是的,这就是问题所在。我正在使用一个带有一些参数的完成块。但是,NSOperationClass 已经有一个名为completionBlock 的属性。因此,我将 completionBlock 更改为 completedBlock,一切正常。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-08
    • 2012-03-02
    • 1970-01-01
    相关资源
    最近更新 更多