Objective-C中的块是否可以将nil值作为参数?

Bre*_*nan 1 objective-c grand-central-dispatch objective-c-blocks

以下代码下载图像并使用块返回结果,以便我可以利用块和Grand Central Dispatch的异步功能.我发现如果图像或错误对象为零,我会收到EXC_BAD_ACCESS错误.如果参数的值为零,它总是会导致错误吗?

失败的部分是returnImage块,用于在方法结束时返回图像.

- (void)downloadImageWithBlock:(void (^)(UIImage *image, NSError *error))returnImage {
    dispatch_queue_t callerQueue = dispatch_get_current_queue();
    dispatch_queue_t downloadQueue = dispatch_queue_create("Image Downloader Queue", NULL);
    dispatch_async(downloadQueue, ^{
        UIImage *image = nil;
        NSError *error;

        // get the UIImage using imageURL (ivar)

        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"Downloading: %@", imageURL);
        });

        NSURL *url = [NSURL URLWithString:imageURL];
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

        NSURLResponse *urlResponse = nil;
        NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&error];

        if (!error && response) {
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@"Success!");
            });
            image = [UIImage imageWithData:response];
        }

        // image will be nil if the request failed

        dispatch_async(callerQueue, ^{
            returnImage(image, error);
        });
    });
    dispatch_release(downloadQueue);
}
Run Code Online (Sandbox Code Playgroud)

下面是我不知道如何阅读的堆栈跟踪.

0x00002d20  <+0000>  push   %ebp
0x00002d21  <+0001>  mov    %esp,%ebp
0x00002d23  <+0003>  sub    $0x18,%esp
0x00002d26  <+0006>  mov    0x8(%ebp),%eax
0x00002d29  <+0009>  mov    %eax,-0x4(%ebp)
0x00002d2c  <+0012>  mov    -0x4(%ebp),%eax
0x00002d2f  <+0015>  mov    0x14(%eax),%eax
0x00002d32  <+0018>  mov    %eax,(%esp)
0x00002d35  <+0021>  movl   $0x3,0x4(%esp)
0x00002d3d  <+0029>  call   0x314c <dyld_stub__Block_object_dispose>
0x00002d42  <+0034>  mov    -0x4(%ebp),%eax
0x00002d45  <+0037>  mov    0x18(%eax),%eax
0x00002d48  <+0040>  mov    %eax,(%esp)
0x00002d4b  <+0043>  movl   $0x3,0x4(%esp)
0x00002d53  <+0051>  call   0x314c <dyld_stub__Block_object_dispose>
0x00002d58  <+0056>  mov    -0x4(%ebp),%eax
0x00002d5b  <+0059>  mov    0x1c(%eax),%eax
0x00002d5e  <+0062>  mov    %eax,(%esp)
0x00002d61  <+0065>  movl   $0x7,0x4(%esp)
0x00002d69  <+0073>  call   0x314c <dyld_stub__Block_object_dispose>
0x00002d6e  <+0078>  add    $0x18,%esp
0x00002d71  <+0081>  pop    %ebp
0x00002d72  <+0082>  ret    
0x00002d73  <+0083>  nopw   0x0(%eax,%eax,1)
0x00002d79  <+0089>  nopl   0x0(%eax)
Run Code Online (Sandbox Code Playgroud)

tit*_*coy 5

NSError *error; 创建指向随机/无效内存位置的指针.

如果块中没有发生错误,则不会为其分配新的(有效)值error.因此,当您测试是否error为nil时,您将取消引用无效指针:

NSError *error; // invalid pointer
NSLog(@"%@", error); // crash -- dereferencing invalid pointer
Run Code Online (Sandbox Code Playgroud)

你应该:

  1. 在将错误变量传递给这种性质的方法之前,始终将nil分配给错误变量.
  2. 查阅方法的文档,该文档通常会告诉您错误变量是否根据方法的返回值分配了有效值.

更新:现在,ARC下的本地对象变量默认为nil.

  • +1我想强调一点:Apple [担保](http://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ErrorHandlingCocoa/CreomCustomizeNSError/CreateCustomizeNSError.html#//apple_ref/doc/ uid/TP40001806-CH204-SW1)如果方法指示失败并返回值,则间接返回NSError对象的Cocoa方法将具有有效的错误对象.但是,它们不保证相反:如果方法表明成功,则错误对象将为零.除非方法的直接返回值指示失败,否则检查错误是不正确的. (2认同)
  • @Brennan总结一下:总是先检查返回值.如果返回值表示错误(例如,它是"nil"或"NO"),请检查"NSError"输出参数.将`nil`分配给`NSError`变量并依赖它并不健壮. (2认同)