0

I'm trying to POST a file to an API endpoint using only native code in the background of my app. I have the following code working but this seems incredibly clunky to me.

Is there a cleaner way to achieve this with using only native Objective-C code?

Here is what I've tried:

- (void)sendMyImage:(NSData *)image
{

    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:true];

    NSString *previewApiUrl = @"URL_OF_MY_ENDPOINT"]
    NSMutableURLRequest *request= [[NSMutableURLRequest alloc] init];

    [request setURL:[NSURL URLWithString:previewApiUrl]];
    [request setHTTPMethod:@"POST"];

    NSString *boundary = @"---------------------------14737809831466499882746641449";
    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary];

    [request addValue:contentType forHTTPHeaderField: @"Content-Type"];

    NSMutableData *postbody = [NSMutableData data];
    [postbody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [postbody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"userfile\"; filename=\"%@.jpg\"\r\n", @"MYFILENAME"] dataUsingEncoding:NSUTF8StringEncoding]];
    [postbody appendData:[[NSString stringWithFormat:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [postbody appendData:image];
    [postbody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];

    // Include the auth headers
    [request setValue:@"MYVALUE1" forHTTPHeaderField:@"CUSTOM_AUTH_HEADER_1"];
    [request setValue:@"MYVALUE2" forHTTPHeaderField:@"CUSTOM_AUTH_HEADER_2"];

    [request setHTTPBody:postbody];

    NSOperationQueue *mainQueue = [[NSOperationQueue alloc] init];

    [NSURLConnection sendAsynchronousRequest:request queue:mainQueue completionHandler:^(NSURLResponse *response, NSData *responseData, NSError *error) {
        NSHTTPURLResponse *urlResponse = (NSHTTPURLResponse *)response;
        [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:false];
        if (!error) {

            NSString *jsonString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]; //parse my JSON response
        }
        else {
                // Handle error condition
        }
    }];
}
Nick
  • 3
  • 2
  • I don't think so, you need to set all these parameters, thats why the world uses third-party API's :) – ManicMonkOnMac Oct 29 '13 at 15:31
  • Just curious: what's your objection to using a 3rd party library? – Aaron Brager Oct 29 '13 at 15:36
  • @AaronBrager I'm building a .framework file/bundle that will be published for partnering apps and wanted to cut out the dependencies – Nick Oct 29 '13 at 15:40
  • refer this post to upload image or any other file [here for objective c](http://stackoverflow.com/questions/11084403/uploading-image-via-post-in-objective-c/15477035#15477035) - Good Luck – Dipen Panchasara Oct 29 '13 at 15:43
  • @Nick You should be able to use a framework like AFNetworking, entirely in your implementation and keep it out of your interface. That will give you the benefits of lots of active 3rd party support, and if you ever want to stop using it, you can just modify your implementation and nobody else will need to change their code. – Aaron Brager Oct 29 '13 at 15:47
  • @AaronBrager Thanks very much- I was wondering exactly this. I want to make this as easy as dropping in the .framework & bundle. If I include something like AFNetworking inside of there, will another developer have to do anything else? Looks like to install you have to use cocoapods, create a pod file etc, don't want a user to have to do this. – Nick Oct 29 '13 at 15:55

1 Answers1

1

Is there a cleaner way to achieve this with using only native Objective-C code?

No, this is how you do it. You could make it look cleaner by encapsulating parts of your logic into separate methods. You also have some verbose stuff that could be removed. (Why use [NSData dataWithData:image] instead of image? Why set maxConcurrentOperationCount when you're only adding one operation?)

Aaron Brager
  • 65,323
  • 19
  • 161
  • 287