cs193p – Assignment #6 Part #5

cs193p – Assignment #6 Part #5

Please note, this blog entry is from a previous course. You might want to check out the current one.

Photo Downloads using Background Fetch

Assignment #6 Task #7

Fetch the URLforRecentGeoreferencedPhotos from Flickr periodically (a few times an hour when your application is in the foreground and whenever the system will allow when it is in the background using the background fetching API in iOS). You must load this data into a Core Data database with whatever schema you feel you need to do the rest of this assignment.

To set up a background fetch, you only need to tell the app what to do when it gets called while it is in the background. In our case: load photos. If the download works, do something with the photos then call the provided completion handler, letting it know that there is new data. If it fails call the completion handler and tell it that the download did not work:

- (void)application:(UIApplication *)application
performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
    [FlickrHelper loadRecentPhotosOnCompletion:^(NSArray *photos, NSError *error) {
        if (error) {
            NSLog(@"Flickr background fetch failed: %@", error.localizedDescription);
        } else {
            NSLog(@"%d photos fetched", [photos count]);

Note that I use the ephemeral download from part #2 instead of the background download from part #3. When this method gets called the app is already in the background. Starting background downloads would mean that the device can decide when to actually start those downloads … probably never …

However, because we want to be “good background citizens”, we adjust the helper function to do not start downloads when there is only a cellular network available, and we limit the download timeout:

+ (void)loadRecentPhotosOnCompletion:(void (^)(NSArray *places, NSError *error))completionHandler
    config.allowsCellularAccess = NO;
    config.timeoutIntervalForRequest = BACKGROUND_FLICKR_FETCH_TIMEOUT;

… but we need to tell the app, that we would like to get called as often as possible, if it is convenient (for the device):

- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    [[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];

Testing this part is possible using Xcode via Debug -> Simulate Background Fetch. Or you can create a new scheme with background fetch enabled during startup:

cs193p – assignment #6 task #1 - launch due to background fetch
launch due to background fetch

The complete code for tasks #1 to #7 is available on github.


5 thoughts on “cs193p – Assignment #6 Part #5”

  1. I am confused with “foreground” and “background”…

    The startFlickrFetch works in “foreground” application, and in this application we use a “background” “downloadSession”?

    And this one does the “background” fetching when we are not the “foreground” application?

    Why we need a background downloadSession when startFlickrFetch only works in foreground mode?

    And why we create do background fetching when a background downloadSession is already exist?

    What the part 2 does? a foreground downloadSession works in foreground application?

    So to be clear, the problem is what’s the foreground, background application and foreground, background download session?

    1. When the app is running on screen (foreground), downloads are triggered at the start and via the timer every 15 minutes as background downloads. Thus you could immediately after the trigger close the app, the download would finish and even relaunch the app off screen to finish the task filling the database.
      When the app is running off screen (background), downloads are triggered whenever the system calls the app as ephemeral downloads. The app will stay off screen and if it succeeds to download data in the limited time available, process it.

      1. Thank you so much! That’s a great explanation!

        So the background fetch in this Part really works when application is on the background.

        The downloadSession in Part#2 works when application is on the foreground. But why people call it background downloadSession, however it only works when application is on the foreground?

          1. Yes, that’s the explanation of backgroundSessionConfigurationWithIdentifier!

            From what I am understand in Apple’s document, NSURLSession do the background download work while system (not user) terminates the app.

            The difference between this and background fetch is the latter downloads the content regularly but not guarantees to do it…

            So that’s why I noticed my app still do foreground fetch when it’s on the background.

            In apple’s document, it’s written “when a good opportunity arises, the system … calls the app delegate’s performFetchWithComletionHandler”.

            “a good opportunity” is a mystery…

Leave a Reply

Your email address will not be published.