Ich habe ein UIScrollView, in dem eine Reihe von Bildern Seite an Seite geladen ist. Sie können ein Beispiel meiner App hier sehen: http://www.42restaurants.com. Mein Problem tritt bei der Speichernutzung auf. Ich möchte die Bilder langsam laden, während sie auf dem Bildschirm erscheinen, und Bilder entladen, die nicht auf dem Bildschirm sind. Wie Sie im Code sehen können, erarbeite ich mindestens das Bild, das ich laden muss, und ordne dann den Ladebereich einer NSOperation zu und platziere sie auf einer NSOperationQueue. Alles funktioniert gut, abgesehen von einem ruckartigen Scroll-Erlebnis.Optimiertes Laden von Bildern in ein UIScrollView
Ich weiß nicht, ob jemand irgendwelche Ideen hat, wie ich das noch optimaler machen kann, damit die Ladezeit jedes Bildes minimiert wird oder damit das Scrollen weniger ruckelt.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
[self manageThumbs];
}
- (void) manageThumbs{
int centerIndex = [self centerThumbIndex];
if(lastCenterIndex == centerIndex){
return;
}
if(centerIndex >= totalThumbs){
return;
}
NSRange unloadRange;
NSRange loadRange;
int totalChange = lastCenterIndex - centerIndex;
if(totalChange > 0){ //scrolling backwards
loadRange.length = fabsf(totalChange);
loadRange.location = centerIndex - 5;
unloadRange.length = fabsf(totalChange);
unloadRange.location = centerIndex + 6;
}else if(totalChange < 0){ //scrolling forwards
unloadRange.length = fabsf(totalChange);
unloadRange.location = centerIndex - 6;
loadRange.length = fabsf(totalChange);
loadRange.location = centerIndex + 5;
}
[self unloadImages:unloadRange];
[self loadImages:loadRange];
lastCenterIndex = centerIndex;
return;
}
- (void) unloadImages:(NSRange)range{
UIScrollView *scrollView = (UIScrollView *)[[self.view subviews] objectAtIndex:0];
for(int i = 0; i < range.length && range.location + i < [scrollView.subviews count]; i++){
UIView *subview = [scrollView.subviews objectAtIndex:(range.location + i)];
if(subview != nil && [subview isKindOfClass:[ThumbnailView class]]){
ThumbnailView *thumbView = (ThumbnailView *)subview;
if(thumbView.loaded){
UnloadImageOperation *unloadOperation = [[UnloadImageOperation alloc] initWithOperableImage:thumbView];
[queue addOperation:unloadOperation];
[unloadOperation release];
}
}
}
}
- (void) loadImages:(NSRange)range{
UIScrollView *scrollView = (UIScrollView *)[[self.view subviews] objectAtIndex:0];
for(int i = 0; i < range.length && range.location + i < [scrollView.subviews count]; i++){
UIView *subview = [scrollView.subviews objectAtIndex:(range.location + i)];
if(subview != nil && [subview isKindOfClass:[ThumbnailView class]]){
ThumbnailView *thumbView = (ThumbnailView *)subview;
if(!thumbView.loaded){
LoadImageOperation *loadOperation = [[LoadImageOperation alloc] initWithOperableImage:thumbView];
[queue addOperation:loadOperation];
[loadOperation release];
}
}
}
}
EDIT: Vielen Dank für die wirklich großen Antworten. Hier ist mein NSOperation-Code und ThumbnailView-Code. Ich habe ein paar Dinge über das Wochenende ausprobiert, aber ich habe es nur geschafft, die Leistung zu verbessern, indem ich die Arbeitswarteschlange während des Scrollens aufgehalten und wieder aufgenommen habe, wenn das Scrollen beendet ist.
Hier sind meine Code-Schnipsel:
//In the init method
queue = [[NSOperationQueue alloc] init];
[queue setMaxConcurrentOperationCount:4];
//In the thumbnail view the loadImage and unloadImage methods
- (void) loadImage{
if(!loaded){
NSString *filename = [NSString stringWithFormat:@"%03d-cover-front", recipe.identifier, recipe.identifier];
NSString *directory = [NSString stringWithFormat:@"RestaurantContent/%03d", recipe.identifier];
NSString *path = [[NSBundle mainBundle] pathForResource:filename ofType:@"png" inDirectory:directory];
UIImage *image = [UIImage imageWithContentsOfFile:path];
imageView = [[ImageView alloc] initWithImage:image andFrame:CGRectMake(0.0f, 0.0f, 176.0f, 262.0f)];
[self addSubview:imageView];
[self sendSubviewToBack:imageView];
[imageView release];
loaded = YES;
}
}
- (void) unloadImage{
if(loaded){
[imageView removeFromSuperview];
imageView = nil;
loaded = NO;
}
}
meine Last Dann und entladen Operationen:
- (id) initWithOperableImage:(id<OperableImage>) anOperableImage{
self = [super init];
if (self != nil) {
self.image = anOperableImage;
}
return self;
}
//This is the main method in the load image operation
- (void)main {
[image loadImage];
}
//This is the main method in the unload image operation
- (void)main {
[image unloadImage];
}
Danke dafür. Ich werde auf jeden Fall einen Blick darauf werfen. –