【问题标题】:Can a block in Objective-C take a nil value as a parameter?Objective-C 中的块可以将 nil 值作为参数吗?
【发布时间】:2011-05-23 23:41:07
【问题描述】:

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

失败的部分是用于在方法结束时返回图像的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);
}

下面是堆栈跟踪,我不知道如何阅读。

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)

【问题讨论】:

  • 使调试此代码变得困难的原因是错误不会出现在一行代码中,因此我必须注释掉代码块以尝试确定错误发生的位置。查明错误的代码行很困难。

标签: objective-c grand-central-dispatch objective-c-blocks


【解决方案1】:

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

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

NSError *error; // invalid pointer
NSLog(@"%@", error); // crash -- dereferencing invalid pointer

您应该:

  1. 始终将 nil 分配给错误变量,然后再将它们传递给这种性质的方法。
  2. 请参阅方法的文档,该文档通常会告诉您错误变量是否已根据方法的返回值分配了有效值。

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

【讨论】:

  • +1 我只想强调一点:Apple guarantees 如果间接返回 NSError 对象的 Cocoa 方法通过其返回值指示失败,则该方法将具有有效的错误对象。但是,它们不保证反过来:如果方法指示成功,则错误对象将为 nil。除非方法的直接返回值表示失败,否则检查错误是不正确的。
  • 感谢杰森和乔希。现在这是有道理的。当它只是一个局部变量问题时,我在想不知何故这是一个 GCD 问题。我还将作为 ivar 的 imageURL 的值设置为局部变量,这样它就不会成为块中的问题。现在代码运行得非常可靠。我确实发现我需要检查 HTTP 状态代码,因为没有错误并不意味着我没有得到 403 或 404 等。我现在需要 200 才能成功。
  • @Brennan 总结一下:总是先检查返回值。如果返回值指示错误(例如,它是nil 或NO),请检查NSError 输出参数。将nil 分配给NSError 变量并依赖它并不可靠。
【解决方案2】:

以下几点可能会有所帮助:

除非响应为零,否则您不应检查错误或对错误做出任何假设。

如果响应不为零,则错误未定义,但您要求块保留错误。你确定这不是你的问题吗?

你确定 returnImage() 可以处理 nils(或未定义的 NSError *)吗?

【讨论】:

  • 一般来说,不将 NSError 指针设置为 nil 是没有意义的,尽管运行时会自动为我们这样做。 @Brennan 发布堆栈跟踪并检查 callerQueue。
  • 我已将堆栈跟踪添加到问题中。
  • 在声明时将 error 设置为 nil 现在允许它在没有异常的情况下运行。我不确定这里发生了什么。
  • @TheBlack:运行时不会将 NSError(或任何其他)指针设置为 nil,除非它们是实例变量,这里不是这种情况。跨度>
  • @TheBlack,我不确定运行时会自动执行此操作是什么意思?你能解释一下吗? @Brennan,我认为问题是在未定义“错误”时尝试[错误保留](或者可能释放?)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-25
  • 1970-01-01
  • 2013-06-15
  • 2020-09-16
  • 1970-01-01
  • 2010-10-05
相关资源
最近更新 更多