5

I'm trying to upload an image to Parse and associate it with a PFObject in my share extension however I'm not sure how to properly do this given the constraints around writing a share extension.

My first attempt at this is as follows using PFFile and PFObject classes

// Create the UserPhoto PFObject and associate with PFFile 
PFObject *userPhoto = [PFObject objectWithClassName:@"UserPhoto"];
userPhoto[@"message"] = @"my photo";
NSData *imageData = UIImageJPEGRepresentation(image, 0.2);
PFFile *imageFile = [PFFile fileWithName:@"image.jpg" data:imageData];
userPhoto[@"imageFile"] = imageFile;

[userPhoto saveInBackground];

The problem with this approach is that if saveInBackground has not completed when the app extension is destroyed the upload will be terminated so you must use NSURLSession to keep the connection alive according to app extension documentation.

NSURLSession can't be used in conjunction with with Parse classes therefore I must use the Parse REST API to initiate the photo upload and then once the photo is uploaded associate the url with an object.

Upload Photo -> Associate photo URL with object

This sets up the upload task to upload an image to Parse

// [self backroundSession] just configures a session and returns it
NSURLSession *session = [self backgroundSession];
NSURL *url = [NSURL URLWithString:@"https://api.parse.com/1/files/pic.jpg"];
NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:url];
[req addValue:@"12345" forHTTPHeaderField:@"X-Parse-Application-Id"];
[req addValue:@"12345" forHTTPHeaderField:@"X-Parse-REST-API-Key"];
[req addValue:@"image/jpeg" forHTTPHeaderField:@"Content-Type"];
[req setHTTPMethod:@"POST"];
// path is the location of the image to be uploaded
NSURLSessionUploadTask *myTask = [session uploadTaskWithRequest:req fromFile:[NSURL fileURLWithPath:path]];
[myTask resume];

Once the photo upload completes we must associate the url with an object. Just like above, I'm creating an object called UserPhoto

- (void)URLSession:(NSURLSession *)mySession task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error {
    // note: this bg session doesn't set delegate so we only create the UserPhoto object once  
    NSURLSession *session = [self backgroundSessionForUserPhoto];

    NSURL *url = [NSURL URLWithString:@"https://api.parse.com/1/classes/UserPhoto"];
    NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:url];
    [req addValue:@"12345" forHTTPHeaderField:@"X-Parse-Application-Id"];
    [req addValue:@"12345" forHTTPHeaderField:@"X-Parse-REST-API-Key"];
    [req addValue:[PFUser currentUser].sessionToken forHTTPHeaderField: @"X-Parse-Session-Token"];
    [req addValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    [req setHTTPMethod:@"POST"];

    NSDictionary *jsonDict = @{@"imageFile" : @{@"name" : response[@"url"], @"__type" : @"File"}, @"message" :@"my photo"};
    NSError *error;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonDict
                                                       options:NSJSONWritingPrettyPrinted 
                                                         error:&error];
    if (!error) {
        [req setHTTPBody:jsonData];
        NSURLSessionTask *myTask = [session dataTaskWithRequest:req];

        [myTask resume];
    }
}

Chaining the REST API calls sometimes works and sometimes doesn't resulting in the image being uploaded but the image url not being associated with the UserPhoto therefore I wonder if the OS forbids triggering another NSURLSession once the extension has been destroyed.

So here is my question:

1) Does parse provide an abstraction over NSURLSession that would eliminate the need to use the Parse REST API?

Otherwise

2) How can I safely chain both NSURLSessions so both the image gets uploaded and the image URL is successfully associated with a Parse object?

Adam Levy
  • 97
  • 2
  • 10

0 Answers0