Scroll-Ansicht und Tabellenansicht beim Laden von Bildern von der Festplatte

Ich versuche, die Leistung meiner bildintensiven iPhone-App zu verbessern, indem ich einen festplattenbasierten Bild-Cache verwende, anstatt über das Netzwerk zu gehen. Ich habe meinen Bild-Cache nach dem Vorbild von SDImageCache http: //github.com/rs/SDWebImage/blob/master/SDImageCache.) und ist ziemlich gleich, jedoch ohne asynchrone Cache-Ein- / Ausgabe-Operationen.

Ich habe einige Bildlauf- und Tabellenansichten, die diese Bilder asynchron laden. Befindet sich das Image auf der Festplatte, wird es aus dem Image-Cache geladen. Andernfalls wird eine Netzwerkanforderung gesendet und das nachfolgende Ergebnis im Cache gespeichert.

Das Problem, auf das ich stoße, besteht darin, dass beim Durchsuchen der Bildlauf- oder Tabellenansichten eine merkliche Verzögerung auftritt, wenn das Bild von der Festplatte geladen wird. Insbesondere bei der Animation, in einer Bildlaufansicht von einer Seite zur nächsten zu wechseln, kommt es zu einem kleinen Einfrieren in der Mitte des Übergangs.

Ich habe versucht, dies zu beheben:

Verwenden Sie ein NSOperationQueue- und ein NSInvocationOperation-Objekt, um Festplattenzugriffsanforderungen zu erstellen (auf die gleiche Weise wie bei SDImageCache), aber dies hilft überhaupt nicht bei der Verzögerung.Den Controller-Code für die Bildlaufansicht so einstellen, dass nur Bilder geladen werden, wenn die Bildlaufansicht nicht mehr rollt. Dies bedeutet, dass der Festplattenzugriff nur ausgelöst wird, wenn die Bildlaufansicht nicht mehr angezeigt wird. Wenn ich jedoch sofort versuche, einen Bildlauf zur nächsten Seite durchzuführen, kann ich die Verzögerung feststellen, wenn das Bild von der Festplatte geladen wird.

Gibt es eine Möglichkeit, die Leistung meiner Datenträgerzugriffe zu verbessern oder die Benutzeroberfläche weniger zu beeinträchtigen?

Beachten Sie, dass ich die Bilder auch bereits im Speicher zwischengespeichert habe. Sobald also alles in den Speicher geladen ist, ist die Benutzeroberfläche nett und ansprechend. Wenn die App gestartet wird oder Warnungen zu wenig Arbeitsspeicher ausgegeben werden, treten viele dieser Verzögerungen auf der Benutzeroberfläche auf, wenn Bilder von der Festplatte geladen werden.

Die relevanten Code-Schnipsel finden Sie unten. Ich glaube nicht, dass ich etwas Phantasievolles oder Verrücktes tue. Die Verzögerung scheint auf einem iPhone 3G nicht spürbar zu sein, aber auf einem iPod Touch der 2. Generation ist sie ziemlich offensichtlich.

Bild-Caching-Code:

Hier ist ein relevanter Ausschnitt meines Bild-Caching-Codes. Ziemlich einfach

- (BOOL)hasImageDataForURL:(NSString *)url {
    return [[NSFileManager defaultManager] fileExistsAtPath:[self cacheFilePathForURL:url]];
}

- (NSData *)imageDataForURL:(NSString *)url {
    NSString *filePath = [self cacheFilePathForURL:url];

    // Set file last modification date to help enforce LRU caching policy
    NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
    [attributes setObject:[NSDate date] forKey:NSFileModificationDate];
    [[NSFileManager defaultManager] setAttributes:attributes ofItemAtPath:filePath error:NULL];

    return [NSData dataWithContentsOfFile:filePath];
}

- (void)storeImageData:(NSData *)data forURL:(NSString *)url {
    [[NSFileManager defaultManager] createFileAtPath:[self cacheFilePathForURL:url] contents:data attributes:nil];
}

Scroll View Controller Code

Hier ist ein relevanter Ausschnitt des Codes, den ich zum Anzeigen von Bildern in meinen Bildlaufsteuerungen verwende.

- (void)scrollViewDidScroll:(UIScrollView *)theScrollView {
    CGFloat pageWidth = theScrollView.frame.size.width;
    NSUInteger index = floor((theScrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;

    [self loadImageFor:[NSNumber numberWithInt:index]];
    [self loadImageFor:[NSNumber numberWithInt:index + 1]];
    [self loadImageFor:[NSNumber numberWithInt:index - 1]];
}

- (void)loadImageFor:(NSNumber *)index {
    if ([index intValue] < 0 || [index intValue] >= [self.photoData count]) {
        return;
    }

    // ... initialize an image loader object that accesses the disk image cache or makes a network request

    UIView *iew = [self.views objectForKey:index];    
    UIImageView *imageView = (UIImageView *) [view viewWithTag:kImageViewTag];
    if (imageView.image == nil) {
        NSDictionary *photo = [self.photoData objectAtIndex:[index intValue]];
        [loader loadImage:[photo objectForKey:@"url"]];
    }
}

Das Image Loader-Objekt ist nur ein kompaktes Objekt, das den Festplatten-Cache überprüft und entscheidet, ob ein Image von der Festplatte oder vom Netzwerk abgerufen werden soll. Sobald dies erledigt ist, ruft es eine Methode auf dem Scroll-View-Controller auf, um das Bild anzuzeigen:

- (void)imageLoadedFor:(NSNumber *)index image:(UIImage *)image {
    // Cache image in memory
    // ...

    UIView *view = [self.views objectForKey:index];
    UIImageView *imageView = (UIImageView *) [view viewWithTag:kImageViewTag];
    imageView.contentMode = UIViewContentModeScaleAspectFill;
    imageView.image = image;
}

AKTUALISIERE

Ich habe mit der App experimentiert und den Bild-Cache deaktiviert und bin darauf zurückgekommen, immer Netzwerkanforderungen zu stellen. Es sieht so aus, als ob die Verwendung von Netzwerkanforderungen zum Abrufen von Bildern @ is Verursacht auch die gleiche Verzögerung beim Scrollen durch Scrollansichten und Tabellenansichten! Das heißt, wenn eine Netzwerkanforderung abgeschlossen ist und das Bild auf der Seite mit der Bildlaufansicht oder in der Tabellenzelle angezeigt wird, bleibt die Benutzeroberfläche ein wenig zurück und weist einige Sekunden Verzögerung auf, während ich versuche, sie zu ziehen.

Die Verzögerung scheint bei Verwendung des Festplatten-Cache nur deutlicher zu sein, da die Verzögerung immer direkt am Seitenübergang auftritt. Vielleicht mache ich etwas falsch, wenn ich das geladene Bild der entsprechenden UIImageView zuordne?

Auch - Ich habe versucht, kleine Bilder (50x50 Thumbnails) zu verwenden, und die Verzögerung scheint sich zu verbessern. Es scheint also, dass der Leistungseinbruch darauf zurückzuführen ist, dass entweder ein großes Bild von der Festplatte oder ein großes Bild in ein UIImage-Objekt geladen wird. Ich denke, eine Verbesserung wäre, die Größe der Bilder, die in die Bildlauf- und Tabellenansicht geladen werden, zu reduzieren, was ich dennoch vorhatte. Ich verstehe jedoch nicht, wie andere fotointensive Apps in der Lage sind, Fotos mit hoher Auflösung in scrollbaren Ansichten darzustellen, ohne dass Leistungsprobleme auf die Festplatte oder über das Netzwerk auftreten.

Antworten auf die Frage(10)

Ihre Antwort auf die Frage