2

I have accomplished lazy loading in a scrollView like this:

-(void)scrollViewDidScroll:(UIScrollView *)myScrollView {

    int currentPage = (1 + myScrollView.contentOffset.x / kXItemSpacingIphone);
    for (ItemView* itemView in [self.itemRow subviews]){
        if (itemView.tag >= currentPage-2 && itemView.tag <= currentPage+2)
        {
            //keep it visible
            if (!itemView.isLoaded) {
                [itemView layoutWithData:[self.items objectAtIndex:itemView.tag-1]];
            }
        }
        else
        {
            //hide it
            if (itemView.isLoaded) {
                [itemView unloadData];
            }

        }
    }
}

Basically loading the view if it's +/- 2 "pages" from being on screen. This greatly reduces the amount of memory I'm using (instead of loading 20+ ItemViews at once), which is good. However, all the loading/unloading does make the scrolling a bit choppy especially on slower devices. Here is what is actually happening on the ItemView loading:

- (void)layoutWithData:(Item*)_data {
    self.data = _data;

//grab the image from the bundle
    UIImage *img;
    NSString *filePath = [[NSBundle mainBundle] pathForResource:_data.image ofType:@"jpg"];
        if(filePath.length > 0 && filePath != (id)[NSNull null]) {
            img = [UIImage imageWithContentsOfFile:filePath];
        }

    UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
    [btn setImage:img forState:UIControlStateNormal];
    [btn addTarget:self action:@selector(tapDetected:) forControlEvents:UIControlEventTouchUpInside];
    btn.frame = CGRectMake(0, 0, kItemPosterWidthIphone, kItemPosterHeightIphone);
    [self addSubview:btn];

    self.isLoaded = YES;

}

And the ItemView unloading:

- (void)unloadData{
    for(UIView *subview in [self subviews]) {
        [subview removeFromSuperview];
    }
    self.data = nil;
    self.isLoaded = NO;
}

Again, what can I do to make the loading/unloading faster and therefore the UIScrollView more smooth?


Attempting async:

- (void)layoutWithData:(Item*)_data {
    self.data = _data;
    self.isLoaded = YES;

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
        UIImage *img;
        NSString *filePath = [[NSBundle mainBundle] pathForResource:_data.image ofType:@"jpg"];
            if(filePath.length > 0 && filePath != (id)[NSNull null]) {
                img = [UIImage imageWithContentsOfFile:filePath];
            }

        dispatch_async(dispatch_get_main_queue(), ^{
            UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
            [btn setImage:img forState:UIControlStateNormal];
            [btn addTarget:self action:@selector(tapDetected:) forControlEvents:UIControlEventTouchUpInside];
            btn.frame = CGRectMake(0, 0, kItemPosterWidthIphone, kItemPosterHeightIphone);
            self.imageView = btn;
            [self addSubview:btn];


        });

    });
}
soleil
  • 12,133
  • 33
  • 112
  • 183

1 Answers1

4

I ran into this problem a while back and I moved loading images from disk to a background thread. Try it and see if it's faster.

See here: loading images from disk in iPhone app is slow

Edit: image loading lags could also be caused by delayed processing of UIImages

See here: Setting image property of UIImageView causes major lag

Community
  • 1
  • 1
yuf
  • 3,082
  • 3
  • 20
  • 18
  • Good suggestion. Unfortunately it's still laggy on older devices. Can you have a look at my edit, under "Attempting async", and see if I'm doing anything wrong? – soleil Oct 10 '12 at 22:40
  • Maybe on slower devices, drawing it on screen is making it lag. I got around the problem with using thumbnails (aka lower quality images) for slower devices. You are loading the images in a background thread correctly. Are your images really HD? Do they need to be that HD? – yuf Oct 10 '12 at 22:52
  • Hi, please read this question: http://stackoverflow.com/questions/10790183/setting-image-property-of-uiimageview-causes-major-lag It could be your problem – yuf Oct 10 '12 at 23:01
  • Thanks, that looks promising too. But I get errors: : CGContextDrawImage: invalid context 0x0 – soleil Oct 10 '12 at 23:28
  • And this: CGBitmapContextCreateImage: invalid context 0x0 – soleil Oct 10 '12 at 23:29
  • Do I have to somehow move this code to drawRect: since it's a UIView subclass? – soleil Oct 10 '12 at 23:31
  • Nevermind, I had to use CGImageCreateWithJPEGDataProvider because my images are jpegs. This works great. Much appreciated. – soleil Oct 10 '12 at 23:40
  • Np. In drawRect there is a default context, but you can make your own when you're not in drawRect. For you, the error was because you used the wrong creation method, but I've had it happen when I specified the size (width or height) of the context as 0 by accident. – yuf Oct 10 '12 at 23:44