2010-11-30 17 views
5

Ben bir URL'den bir görüntü yükler bir iPad uygulamasının yazmaya çalışıyorum URL'den UIImage kullanarak resim yüklerken.Önemli gecikme uyumsuz

url = [NSURL URLWithString:theURLString]; 
    NSData *data = [NSData dataWithContentsOfURL:url]; 
    img = [[UIImage alloc] initWithData:data]; 
    [imageView setImage:img]; 
    [img release]; 
    NSLog(@"Image reloaded"); 

o zaman uyumsuz değil yük resmin websever yavaşsa kilitlemek Uygulamamı neden olacaktır böylece kod Bütün bir operasyon olarak NSOperationQueue ekleniyor: Aşağıdaki görüntü yükleme kodunu kullanıyorum. NSLog satırını ekledim, böylece bu kod çalıştırıldığında konsolda görebiliyordum.

Uygulamanın kodun çalışmasını bitirdikten yaklaşık 5 saniye sonra uygulamamın güncellendiğini sürekli olarak fark ettim. Ancak, bu kodu NSOperationQUeue ürününe koymadan kullanabiliyorsam, görüntüyü hemen hemen günceller.

Gecikme yavaş bir web sunucusundan kaynaklanmıyor ... Resim URL'sini Safari'de yükleyebilirim ve yüklemek için bir saniyeden daha az sürüyor ya da NSOperationQueue olmadan aynı kodla yükleyebilirim. çok daha hızlı yüklenir.

Görüntüm görüntülenmeden önce gecikmeyi azaltmanın bir yolu var mı, ancak bir NSOperationQueue kullanmaya devam edilsin mi?

cevap

6

belgelerine göre, yazdığınız kodu geçersiz. UIKit nesneleri herhangi bir yere değil, ana iş parçasına çağrılabilir. Bahse girerim, yaptığınız şeyin çoğu açıdan çalıştığı, ancak ekranın başka bir nedenden dolayı tesadüfen güncellenmesiyle, ekranı başarılı bir şekilde değiştirmediği konusunda bahse girerim.

Apple, pilin verimli kalmasını istiyorsanız, iş parçacıklarının eşzamansız URL getirme işlemlerini gerçekleştirme yöntemini önermemesini önemle tavsiye eder. Bunun yerine NSURLConnection kullanmalı ve runloop'un asenkronize davranışlar düzenlemesine izin vermelisiniz. Sadece bir NSData'ya veri toplayan hızlı bir yöntem yazmak o kadar da zor değil, o zaman bağlantıyı tamamladığınızda tüm şeyi bir temsilci üzerine gönderir, ancak önerdiğin şeyle uğraşmayı tercih ederim. : - nesne ana iş parçacığı üzerinde tek parametre olarak kısa sürede binebilirsek çalışma döngüsü olarak verilen nesne ile istenen seçici zamanlayacak gönderilir

url = [NSURL URLWithString:theURLString]; 
NSData *data = [NSData dataWithContentsOfURL:url]; 
[self performSelectorOnMainThread:@selector(setImageViewImage:) withObject:data waitUntilDone:YES]; 

... 

- (void)setImageViewImage:(NSData *)data 
{ 
    img = [[UIImage alloc] initWithData:data]; 
    [imageView setImage:img]; 
    [img release]; 
    NSLog(@"Image reloaded"); 
} 

performSelectorOnMainThread adı söylediğini yapıyor. Bu durumda 'veriler', NSOperation tarafından örtük olarak oluşturulmuş iş parçacığında havuzdaki otomatik olarak çalıştırılan bir nesnedir. Kullanılıncaya kadar geçerli kalmanız gerektiğinden, waitUntilDone:YES kullanıyorum. Bir alternatif, açık bir şekilde sahip olduğunuz ve ana iş parçacığı yönteminin onu serbest bıraktığı bir veri oluşturmaktır.

Bu yöntemin ana dezavantajı, görüntü sıkıştırılmış bir biçimde (JPEG veya PNG gibi) geri dönerse, ana iş parçacığı üzerinde sıkıştırılmış olacaktır. UIImage'ın, güvenli olduğu belgelenmiş olanın üstüne ve ötesine geçen davranışları hakkında ampirik tahminler yapmadan, C seviyesine düşmeniz ve CoreGraphics'i kullanmanız gerekir. Ama bunu, bunu yaparken bu sorunun kapsamı dışında kaldığı için alıyorum.

+0

teşekkür Tommy için! Bu gece bir bakacağım ve bana anlattığın şeyden nereden alabileceğimi göreceğim.Aslında, bu sabah Coacoa'daki görüntüleri indirmenin farklı yollarını okuyordum ve NSUrlRequest ve NSURLConnection kullanarak tüm resim işleme kodunu yeniden yazdığımda, görüntüyü beklediğim gibi yüklediğimi kendi kendime keşfettim. Yazdığım yeni yöntemi mi kullanacağımı ya da bana gösterdiğiniz kodun kullanıp kullanamayacağına hala emin değilim, ancak seçeneklerin mükemmel olması ve her iki yolla yazılması iyi bir öğrenme deneyimiydi. Yardımınız için tekrar teşekkürler ve benim gibi yeni başlayan bir çocukla tanıştığınız için teşekkürler! :) – Jackson

+0

Bu arada, bu soruyu okuyan başka biri varsa, bu makaleyi NSUrlRequest tabanlı bir görüntü yükleyici için çok yararlı buldum. http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLConnection.html – Jackson

1

Tommy ana iş parçacığı üzerinde tüm UIKit şeyler yapmak için ihtiyacı hakkında doğru. Ancak, bir arka plan işlemi kuyruğunda getirme çalıştırıyorsanız, NSURLConnection asenkron yüklemesini kullanmaya gerek yoktur. Ayrıca, görüntü çözme işleminin arka plan işleminde çalışmasını sağlayarak, görüntüyü deşifre ederken ana parçacığın engellenmesini engellersiniz.

Bu kodu olduğu orijinal kodunu kullanmak mümkün, ama sadece [imgView setImage: img] değişmelidir:

[imageView performSelectorOnMainThread:@selector(setImage:) 
          withObject:img 
         waitUntilDone:NO]; 
+0

Vay, bu sorunu çözdü. Çok teşekkürler! Bu çok basit! Yine de neden hala emin değilim. Bunu okumak zorundayım. Artık tam olarak uygulanan ve çalışan bir NSUrlConnection yönteminin (hangisinin eşzamansız olduğunu) ve NSObjectQueue kullanan NSData/dataWithContentsOfURL yöntemini kullanıyorum, hangisini kullanmamı önerirsiniz? NSUrlConnection ve NSData kullanmanın güçlü yanları nelerdir? NSUrlConnection'ın hataları daha iyi önbelleğe alma ve işleme konusunda daha fazla esnekliğe sahip olduğunu duydum. Bu doğru mu? Tekrar teşekkürler! – Jackson

+0

NSURLConnection'ın size daha fazla esneklik sağladığı doğru. Ancak NSURLConnection'ın bir arka plan NSOperation'daki asenkron yüklemesini kullanmak oldukça zordur çünkü kendi çalışma döngüsünüzü ayarlamanız gerekir. NSURLConnection tarafından sunulan esnekliğin bir kısmını (bkz. NSMutableURLRequest) elde etmek için '- [NSURLConnection sendSynchronousRequest: returnningResponse: error:] yöntemini kullanabilirsiniz. Muhtemelen karmaşık HTTP yönlendirmesi/kimlik doğrulaması/önbellekleme gereksinimleriniz olmadıkça bu benim yapacağım şeydir. –

+0

Bu çözümün neden "olduğu" sorusu ise, ana konu üzerinde çalışan görünüm çizim kodunun, sadece resim görüntüsünün görüntüsünü değiştirdiğinizi bilmesi gerektiğidir. SetImage çağırarak: bir arka plan iş parçacığında, büyük ihtimalle çekilecek yeni içeriğin (başka bir şey görünümün yenilenmesine neden olana kadar) ana konuya bildirilmez. Bunu arka plan iş parçacığı üzerinde yaparak daha kötü davranışlar elde edebilirsiniz - ör. Ana iş parçacığı çizmeye çalışırken ortasında görüntü değiştirirseniz. –