Scroll view and table view performance when loading images from disk

后端 未结 5 1506
说谎
说谎 2021-02-04 18:50

I\'m trying to improve the performance of my image-intensive iPhone app by using a disk-based image cache instead of going over the network. I\'ve modeled my image cache after S

相关标签:
5条回答
  • 2021-02-04 19:17

    It's typically the image decoding which takes time, and that causes the UI to freeze (since it's all happening on the main thread). Every time you call [UIImage imageWithData:] on a large image, you'll notice a hiccup. Decoding a smaller image is far quicker.

    Two options:

    1. You can load a thumbnail version of each image first, then 'sharpen up' on didFinishScrolling. The thumbnails should decode quickly enough such that you don't skip any frames.
    2. You can load a thumbnail version of each image or show a loading indicator first, then decode the full-resolution image on another thread, and sub it in when it's ready. (This is the technique that is employed in the native Photos app).

    I prefer the second approach; it's easy enough with GDC nowadays.

    0 讨论(0)
  • 2021-02-04 19:24

    You should check out the LazyTableImages sample app.

    0 讨论(0)
  • 2021-02-04 19:27

    I've had this problem - you are hitting the limit of how fast the UI can load an image while scrolling - so i'd just work around the problem and improve the user experience.

    1. Only load images when the scroll is at a new 'page' (static rectangle) and
    2. Put an activity indicator behind a transparent scroll view to handle the case where the user is scrolling faster than the app can load content
    0 讨论(0)
  • 2021-02-04 19:31

    The image from the disk is actually read while drawing the image on the imageview. Even if we cache the image reading from the disk it does not affect since it just keeps reference to the file. You might have to use tiling of larger images for this purpose.

    Regards, Deepa

    0 讨论(0)
  • 2021-02-04 19:38

    If you've narrowed it down to network activity I would try encapsulating your request to ensure it is 100% off of the main thread. While you can use NSURLConnection asynchronously and respond to it's delegate methods, I find it easier to wrap a synchronous request in a background operation. You can use NSOperation or grand central dispatch if your needs are more complex. An (relatively) simple example in an imageLoader implementation could be:

    // imageLoader.m
    
    // assumes that that imageCache uses kvp to look for images
    - (UIImage *)imageForKey:(NSString *)key
    {
        // check if we already have the image in memory
         UImage *image = [_images objectForKey:key];
    
        // if we don't have an image:
        // 1) start a background task to load an image from a file or URL
        // 2) return a default image to display while loading
        if (!image) {
            [self performSelectorInBackground:@selector(loadImageForKey) withObject:key];
            image = [self defaultImage];
        }
    
        return image;
    }
    
    - (void)loadImageForKey:(NSString *)key
    {
        NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init];
    
        // attempt to load the image from the file cache
        UIImage *image = [self imageFromFileForKey:key];
    
        // if no image, load the image from the URL
        if (!image) {
            image = [self imageFromURLForKey:key];
        }
    
        // if no image, return default or imageNotFound image
        if (!image) {
            image = [self notFoundImage];
        }
    
        if ([_delegate respondsTo:@selector(imageLoader:didLoadImage:ForKey:)]) {
            [_delegate imageLoader:self didLoadImage:image forKey:key];
        }
    
        [pool release];
    }
    
    - (UIImage *)imageFromURLForKey:(NSString *)key
    {
        NSError *error = nil;
        NSData *imageData = [NSData dataWithContentsOfURL:[self imageURLForKey:key]
                                                  options:0
                                                    error:&error];
    
        UIImage *image;
    
        // handle error if necessary
        if (error) {
            image = [self errorImage];
        }
    
        // create image from data
        else {
            image = [UIImage imageWithData:imageData];
        }
    
        return image;
    }
    
    0 讨论(0)
提交回复
热议问题