2014-06-18 1 views
0

Я хочу отобразить изображение на экране, которое я беру из Интернета. Я использовал NSURLConnection, чтобы создать асинхронный вызов, чтобы взять данные, и в блоке ответа я вызвал код, чтобы назначить его объекту UIImage.iOS: Почему мне нужно использовать сон (1) после NSURLConnection sendAsynchronousRequest?

Мой вопрос, почему мне нужно вызвать sleep (1) после выполнения блока? Если я не назову его, тогда мое изображение не будет нарисовано на экране. Это еще один, более элегантный способ добиться этого?

-(void)loadImage:(NSString *)url 
{ 
    NSURL *imageURL = [NSURL URLWithString:url]; 
    NSOperationQueue *queue = [[NSOperationQueue alloc]init]; 
    NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageURL cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:5.0f]; 
    [NSURLConnection sendAsynchronousRequest:imageRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { 
     if(!connectionError) { 
      if(data) { 
       //there goes the main thingy 
       self.myView.wallpaperImage = [UIImage imageWithData:data]; 
       [self.myView setNeedsDisplay]; 
      } else { 
       NSLog(@"No data found at url:%@",url); 
      } 
     } else { 
      NSLog(@"Could not connect to %@",url); 
     } 
    }]; 
    sleep(1); 
} 
+3

Никогда не называйте 'sleep()'. – zaph

+0

Возможно, я спрашивал не так ... Я знаю, что мне не нужно это называть, но если я этого не сделаю, у меня ничего нет, кроме белого экрана. Если я вызываю сон, тогда изображение рисуется без проблем. – Bogdan

+4

Убедитесь, что все вызовы UIKit выполняются в главной очереди. – Jiri

ответ

2

Это:

self.myView.wallpaperImage = [UIImage imageWithData:data]; 
[self.myView setNeedsDisplay]; 

происходит на нити управляемой NSOperationQueue передается sendAsynchronousRequest. Эти методы нужно вызывать из основного потока. Ваш сон может вызывать переборку основного потока, после чего эти вызовы, похоже, сработали. Чтобы это исправить, и, чтобы избежать целой кучи других проблем, текущий подход будет иметь, сделать это:

[NSURLConnection sendAsynchronousRequest:imageRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { 
     if([data length] > 0) { 
      //there goes the main thingy 
      [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 
       self.myView.wallpaperImage = [UIImage imageWithData:data]; 
       [self.myView setNeedsDisplay]; 
      }]; 
     } else { 
      // Perform your error handling here. 

     } 
    }]; 

Это будет использовать [NSOperationQueue mainQueue] выполнять те UIKit вызовов от основной очереди - не libdispatch. libdispatch - это низкоуровневый интерфейс, рекомендуется всегда предпочитать интерфейс более высокого уровня - в данном случае NSOperationQueue. UIKit безопасен только при вызове из основного потока (или очереди). Он также изменяет поведение обработки ошибок, чтобы следовать за bestpractices для platform - проверить результат вашего вызова (в данном случае, данные) и затем обработать любую ошибку.

Ваш код на самом деле является хорошим примером того, почему блоки сохраняют захваченные объекты (в данном случае я). Если бы здесь не было цикла удержания, ARC мог бы уничтожить queue, как только он выйдет за пределы области действия, и блок никогда не выполнит. Вместо этого из-за цикла сохранения очередь остается вокруг до тех пор, пока блок не выполнит.

+0

Благодарим вас за подробное объяснение. – Bogdan

 Смежные вопросы

  • Нет связанных вопросов^_^