pixeldock

iOS, Cocoa Touch, Objective-C and more…

NSURLConnection: How to avoid blocked file loading during scrolling of UIScrollView or UITableView

Posted: | Author: | Filed under: iOS | Tags: , , | 6 Comments »

When you want to load a file (like a large image) into your app, you don’t want to block the user interface during the loading. It’s always a good idea to load large files asynchronously.

The easiest way to load a file in the background is via NSURLConnection.

NSURLConnection *connection = [[NSURLConnection alloc] 
     initWithRequest:request delegate:self startImmediately:NO];
[connection start];

However, if you use the default settings the connection object will be scheduled in the NSDefaultRunLoopMode. That means that the connection is only executing the request when the app’s run loop is in NSDefaultRunLoopMode.

Now, when a user touches the screen (e.g. to scroll a UIScrollView) the run loop’s mode will be switched to NSEventTrackingRunLoopMode. And now, that the run loop is not in NSDefaultRunMode anymore, the connection will not execute. The ugly effect of that is, that the download is blocked whenever the user touches the screen. And that can be a looong time when the user is scrolling a UITableView, because the download is stopped until the scrolling completely stops. And when the user continues to scroll, the download is blocked again.

Fortunately the solution to this problem is quite simple: You can schedule the connection in another NSRunLoopMode. When you schedule the connection in NSRunLoopCommonModes it will execute in all run loop modes (that have been declared as a member of the set of “common” modes, to be precise). That means that the connection is not only working in NSDefaultRunLoopMode but also in NSEventTrackingRunLoopMode (when the user touches the screen).

[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] 
     forMode:NSRunLoopCommonModes];

Bingo! The async file loading is not blocked anymore during user interaction.

6 Comments

  • 1

    Alessandrosaid at

    Thank you! I’ve solved my problem :-)

  • 2

    Pansaid at

    I tried this in the Apple Sample code: LazyTableImages, but didn’t work like you said. I just add one line in this method:
    - (void)startDownload
    {
    self.activeDownload = [NSMutableData data];
    // alloc+init and start an NSURLConnection; release on completion/failure
    NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:
    [NSURLRequest requestWithURL:
    [NSURL URLWithString:appRecord.imageURLString]] delegate:self];

    [conn scheduleInRunLoop:[NSRunLoop currentRunLoop]
    forMode:NSRunLoopCommonModes];
    self.imageConnection = conn;

    [conn release];

    }
    Why? Thanks

  • 3

    pansaid at

    My bad, i just misunderstand the effect of this line. It seems working.
    When i scrolling the screent, it didn’t show the images,then when stops, it shows the images kinda instantly.
    This is the effect,right?
    Thanks

  • 4

    adminsaid at

    Hi pan,
    yes, that is the effect if you don’t schedule your connection in the NSRunLoopCommonModes.
    Best regards,
    Jörn

  • 5

    NSDefaultRunLoopMode vs NSRunLoopCommonModessaid at

    [...] process gets halted as soon as I touch iPhone screen. Thankfully, an awesome blog post by Jörn suggests an alternative option, using NSRunLoopCommonModes for [...]

  • 6

    Franksaid at

    Genius..


Leave a Reply