3

More of a general question - I don't understand the workings of NSURLSession when using it in "background session mode". I will supply some simple contrived example code.

I have a database which holds objects - such that portions of this data can be uploaded to a remote server. It is important to know which data/objects were uploaded in order to accurately display information to the user. It is also important to be able to upload to the server in a background task because the app can be killed at any point.

for instance a simple profile picture object:

@interface ProfilePicture : NSObject

@property int userId;
@property UIImage *profilePicture;
@property BOOL successfullyUploaded; // we want to know if the image was uploaded to out server - this could also be a property that is queryable but lets assume this is attached to this object

@end

Now Lets say I want to upload the profile picture to a remote server - I could do something like:

@implementation ProfilePictureUploader

-(void)uploadProfilePicture:(ProfilePicture *)profilePicture completion:(void(^)(BOOL successInUploading))completion
{
     NSUrlSession *uploadImageSession = ..... // code to setup uploading the image - and calling the completion handler;
     [uploadImageSession resume];
}

@end

Now somewhere else in my code I want to upload the profile picture - and if it was successful update the UI and the database that this action happened:

ProfilePicture *aNewProfilePicture = ...;
aNewProfilePicture.profilePicture = aImage;
aNewProfilePicture.userId = 123;
aNewProfilePicture.successfullyUploaded = NO;

// write the change to disk
[MyDatabase write:aNewProfilePicture];

// upload the image to the server
ProfilePictureUploader *uploader = [ProfilePictureUploader ....];
[uploader uploadProfilePicture:aNewProfilePicture completion:^(BOOL successInUploading) {
  if (successInUploading) {
    // persist the change to my db.
    aNewProfilePicture.successfullyUploaded = YES;
    [Mydase update:aNewProfilePicture]; // persist the change 
  }
}];

Now obviously if my app is running then this "ProfilePicture" object is successfully uploaded and all is well - the database object has its own internal workings with data structures/caches and what not. All callbacks that may exist are maintained and the app state is straightforward.

But I'm not clear what happens if the app "dies" at some point during the upload. It seems that any callbacks/notifications are dead. According to the API documentation- the uploading is handled by a separate process. Therefor the upload will continue and my app will be awakened at some point in the future to handle completion. But the object "aNewProfilePicture" is non existant at that point and all callbacks/objects are gone. I don't understand what context exists at this point. How am I supposed to ensure consistency in my DB and UI (For instance update the "successfullyUploaded" property for that user)? Do I need to re-work everything touching the DB or UI to correspond with the new API and work in a context free environment?

Avba
  • 14,822
  • 20
  • 92
  • 192

1 Answers1

0

You can download and upload files using the NSURLSession with a background configuration. You will have to implement NSURLSessionDelegate, NSURLSessionDownloadDelegate, NSURLSessionUploadDelegate. With the background session you cannot use the completion handlers anymore. I found this tutorial to be very helpful to understanding of how background NSURLSession works: http://www.appcoda.com/background-transfer-service-ios7/.

In your case you can do something like this: when you create an upload task, you can assign user's id from your database to 'taskDescription' property of your NSURLSessionTask. When upload is finished, delegate method is called, and you can implement something like this:

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
   int userID = [task.taskDescription intValue];
   [self.database updateUserRecordWithID:userID];
}
almas
  • 7,090
  • 7
  • 33
  • 49
  • I understand that. But my question was about context of the App when in background – Avba Aug 21 '14 at 15:52
  • Your app can be in any state except 'Not running'. Once nsnetwork daemon finishes uploading/downloading your files, your app will be woken up and the delegate method will be called. – almas Aug 21 '14 at 15:56
  • So any state of the app is lost. How can the app know what is the new state it should be in – Avba Aug 21 '14 at 16:04
  • 1
    If your app crashed or whatever, the os will wake you up once upload is finished. In this method - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error you need to recognize what has been uploaded, and then take appropriate action, e.g. update your DB, UI, etc – almas Aug 21 '14 at 16:10