Может ли блок в Objective-C принять нулевое значение в качестве параметра? - PullRequest
1 голос
/ 24 мая 2011

Следующий код, который загружает изображение и возвращает результат с блоком, чтобы я мог воспользоваться асинхронными функциями блоков и 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)

Ответы [ 2 ]

5 голосов
/ 24 мая 2011

NSError *error; создает указатель на случайную / недействительную ячейку памяти.

Если в блоке не возникает ошибка, ему не будет присвоено новое (действительное) значение для error.В результате, когда вы проверяете, равен ли error ноль, вы разыменовываете недопустимый указатель:

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

Вы должны либо:

  1. Всегда назначать ноль переменным ошибки до того, какпередавая их методу такого типа.
  2. Обратитесь к документации метода, которая обычно скажет вам, было ли переменной переменной присвоено действительное значение на основе возвращаемого значения метода.

Обновление: переменные локального объекта теперь по умолчанию равны nil в ARC.

1 голос
/ 24 мая 2011

Итак, пара моментов, которые могут помочь:

Вы не должны проверять ошибку или делать какие-либо предположения об ошибке, если ответ не равен нулю.

Если ответ не ноль, то ошибка не определена, и все же вы просите, чтобы блок сохранил ошибку. Вы уверены, что это не ваша проблема?

Вы уверены, что returnImage () может обрабатывать nils (или неопределенный NSError *)?

...