1

我有一个 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 --> <SKSimpleDownloadOperation: 0x7462be0>

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

4

1 回答 1

4

NSOperation 类参考

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

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

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

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

于 2012-11-14T03:14:11.243 回答