2010-06-28 10 views
8

Bis zu iOS 3.2, habe ich diese Art von Code UIImageView Bild im Hintergrund zu laden, und es funktioniert gut ...iOS4 & Hintergrund [UIImage setImage:]

Code:

- (void)decodeImageName:(NSString *)name 
{ 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    UIImage *newImage = [UIImage imageNamed:name]; 
    [myImageView setImage:newImage]; 
    [pool release]; 
} 
... 
[self performSelectorInBackground:@selector(decodeImageName:) withObject:@"ID"] 

. .. auch wenn [UIImageView setImage:] nicht Thread-sicher war!

Aber seit iOS 4 funktioniert es nicht mehr ... Bilder erscheinen auf dem Bildschirm zwei Sekunden nach setImage Anruf. Und wenn ich einen [myImageView performSelectorOnMainThread:@selector(setImage:) withObject:newImage waitUntilDone:YES] anstelle von [myImageView setImage:newImage] mache, erscheinen Bilder sofort, aber scheinen wieder on-the-fly neu decodiert zu werden (das vorherige [UIImage imageNamed:] ignorierend, das die Bilddaten bereits entschlüsseln musste), eine Pause auf meinem Hauptgewinde verursachend. Auch wenn die Dokumentation sagt Der zugrunde liegende Image-Cache ist unter allen Threads geteilt..

Irgendwelche Gedanken?

+0

Hallo, vielen Dank für Ihre Frage.Ich habe mich gefragt, warum es jetzt nicht mit meiner App funktioniert. – GeneCode

Antwort

3

performSelectorInBackground: startet einen Selektor in einem Hintergrund-Thread. Dennoch setImage: ist eine UI-Funktion. UI-Funktionen sollten nur für den Hauptthread ausgeführt werden. Ich habe keinen Einblick in das spezielle Problem, aber dies ist das erste Gefühl für diesen Code, und es kann sein, dass iOS4 den (nicht unterstützten) Mechanismus zum Ausführen von UI-Funktionen in Hintergrund-Threads irgendwie anders behandelt.

4

Tun Sie es nicht im Hintergrund! Es ist nicht threadsicher. Da ein UIImageView ist auch ein NSObject, denke ich, dass mit -[performSelectorOnMainThread:withObject:waitUntilDone:] auf es könnte funktionieren, wie:

[myImageView performSelectorOnMainThread:@selector(setImage:) withObject:newImage waitUntilDone:NO]; 

Und es ist UIImage die neu Thread-sicher gemacht wird. UIImageView ist immer noch nicht Thread-sicher.

+1

Hallo Evadne, wo hast du gelesen, dass UIImage Thread-sicher ist? Ich kann das nirgendwo finden. – jasongregori

1

Wenn Sie mit iOS 4.0 arbeiten, sollten Sie wirklich betrachten lesen auf Blöcken und GCD. diese Technologien verwenden, können Sie einfach ersetzen Ihre Methode mit:

- (void)decodeImageName:(NSString *)name 
{ 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    UIImage *newImage = [UIImage imageNamed:name]; 

    dispatch_async(dispatch_get_main_queue(), ^{ 
     [myImageView setImage:newImage]; 
    } 

    [pool release]; 
} 
+0

Es hilft nicht viel. Das dispatch_async pausiert den Haupt-Thread noch länger als es sein sollte, als ob das uiimage neu decodiert wurde. Wie kann ich sicher sein, dass die UIImage nach [UIImage imageNamed: name] decodiert wird? –

+0

Ich würde empfehlen, OS 3.1.3 für mindestens mehrere Monate zu unterstützen, und 3.2 bis ein paar Monate nach 4.0+ für iPad veröffentlicht wird. –

1

Lassen Sie uns Zitat:

@property(nonatomic, readonly) CGImageRef CGImage

Diskussion

Wenn die Bilddaten wegen Speicher gelöscht worden Durch das Aufrufen dieser Methode müssen die Daten wieder in den Speicher geladen werden. Das erneute Laden der Bilddaten kann zu einer Leistungseinbuße führen.

So können Sie möglicherweise nur image.CGImage anrufen. Ich glaube nicht CGImages sind faul.

Wenn das nicht funktioniert, können Sie ein mit etwas machen zwingen, wie

// Possibly only safe in the main thread... 
UIGraphicsBeginImageContext((CGSize){1,1}); 
[image drawInRect:(CGRect){1,1}]; 
UIGraphicsEndImageContext(); 

Einige Leute über Thread-Sicherheit warnen. Die Dokumente sagen UIGraphics{Push,Pop,GetCurrent}Context() sind nur Thread-Thread, aber nichts über UIGraphicsBeginImageContext(). Wenn Sie sich Sorgen machen, verwenden Sie CGBitmapContextCreate und CGContextDrawImage.

Verwandte Themen