If you’re like me, you learn by example. Surprisingly, there are not many tutorials out there that make it clear exactly how to upload an image, or any file for that matter, from an iOS device to a server using the iOS preferred native language, Objective C. I have no idea why this is, so here I am, your humble goat author, attempting to rectify this nasty situation.
Before we get underway, this walkthrough utilizes MKNetworkKit, a lightweight ARC framework that wraps primarily around the Core Services network framework. Alright, you’re probably asking why not just use the Core Services network framework. Here’s why: MKNetworkKit provides a single shared network queue application wide, accurately fires the network indicator (yes, this is something you would have to manually manage), manages the number of concurrent connections based on wifi/3G/EDGE, auto caching GET requests (if desired), and operation freezing (if something happens to the connection). Sure, you can write all of this code yourself just like you could build your own jet fighter. I don’t think you should go down that path. Let’s begin.
Install MKNetworkKit
Clone the latest and greatest version of MKNetworkKit over at github. It is important to grab the latest version as there was a small bug with POSTs prior to my commit. Drag the MKNetworkKit directory into your project within Xcode. Make sure to copy the items over if needed. Next, add the following built-in frameworks to your target: CFNetwork.Framework, SystemConfiguration.framework and Security.framework.

Add ‘#import “MKNetworkKit.h”‘ within the PCH file.

MKNetworkKit has support for both iOS and Mac builds. Since we’re building an iOS app, remove the NSAlert+MKNetworkKitAdditions.h and NSAlert+MKNetworkKitAdditions.m files from the categories directory. The MKNetworkKit should be installed! Do a build to ensure you’re good to go. You’ll get some dev triggered warnings and that’s ok. Carry on.
Select the file to upload
For the sake of simplicity, let’s upload a photo. First, add an UIButton to the view and give it a title, “Upload Photo”.

Next, insert an action by pressing Ctrl+C on the UIButton and drag it over to the implementation (.m) file.

Give the user some options when the button is clicked. To accomplish this, use an UIActionSheet. Be sure to add UIActionSheetDelegate to the header file. Within the UIActionSheet’s delegate method, add a switch to determine which option was selected on the UIActionSheet. Within the case statements, create UIImagePickerController objects. Be sure to add the delegates UIImagePickerControllerDelegate and UINavigationControllerDelegate to the header file. For right now, add the UIImagePickerController delegate method with the didFinishPickingMediaWithInfo message. We’ll fill it out in the next step.
Oh! Before you go any further, if you’re using the iOS simulator, use Safari within the simulator to download an image into your simulator’s photo library.
Create a network engine
The MKNetworkEngine object manages the queues, caching, and other connectivity goodness that we, for the most part, don’t have to worry about. To create one, add a new objective C class with the subclass MKNetworkEngine. Our engine will just have one defined method in it, postDataToServer.
POST file to the server
The crescendo of the walkthrough, this is the step where we finally get to reach out and touch someone. Before sending the photo to the server, you’ll definitely want to compress the image using the UIImageJPEGRepresentation method. On top of that, you’ll more than likely want to resize/rotate/crop the image. For this walkthrough, we’re leaving out the later for brevity’s sake. After the compression step, initialize the engine. You’ll want to use the engine as a singleton, initialized within the appDelegate.

To show you how to also pass parameters within the body, I’ve created a dictionary object called postParams. It has one parameter ‘appID’ with the value of ‘testApp’. The network operation, flOperation, is being initialized from our engine’s postDataToServer method. It will pass the postParams dictionary and the POST path. Let’s introduce the compressed image to our network operation. MKNetwork operation has a method called addData that accepts, you guessed it, NSData. Lucky for us, our image is already within an NSData object. Define the success/error blocks and then add the request to the queue. You’re all set!
Handle server response
If you’re following along, character by character, the code will upload a photo and one parameter to posttestserver.com, a server managed by Henry Cipolla. Within the response returned as a result of the POST, his server will respond with a URL that will provide us more information about what we just POSTed. Our success block is very basic, outputting the response to the log (viewed within the right section of the bottom pane). If there’s an error with the request, an UIAlertView will appear.
{
[self dismissModalViewControllerAnimated:YES];
NSData *image = UIImageJPEGRepresentation([info objectForKey:UIImagePickerControllerOriginalImage], 0.1);
self.flUploadEngine = [[fileUploadEngine alloc] initWithHostName:@"posttestserver.com" customHeaderFields:nil];
NSMutableDictionary *postParams = [NSMutableDictionary dictionaryWithObjectsAndKeys:
@"testApp", @"appID",
nil];
self.flOperation = [self.flUploadEngine postDataToServer:postParams path:@"/post.php"];
[self.flOperation addData:image forKey:@"userfl" mimeType:@"image/jpeg" fileName:@"upload.jpg"];
[self.flOperation addCompletionHandler:^(MKNetworkOperation* operation) {
NSLog(@"%@", [operation responseString]);
/*
This is where you handle a successful 200 response
*/
}
errorHandler:^(MKNetworkOperation *errorOp, NSError* error) {
NSLog(@"%@", error);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error"
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:@"Dismiss"
otherButtonTitles:nil];
[alert show];
}];
[self.flUploadEngine enqueueOperation:self.flOperation];
}
That’s all folks. You can find my walkthrough code over at github. If you have any questions or comments about the walkthough, drop a comment or contact me here.


Thanks for the info. Really helped! :)
Hi Mike
Do you have a cope of the server php you could post to round of the tutorial?
Thanks
Justin
Hi Justin, because I didn’t want readers to think this walkthrough would only work with backend language xyz, I didn’t include the server side stuffs. However, if you’re looking for a solid PHP example, check out CodeIgniter’s file upload class documentation.
Hey thanks for putting this together. So far it looks like what Im after but I wondered if you knew the simplest way to add the xib file into an existing storyboard? In other words, I just want the view controller within your storyboard obviously and actually the most ideal situation were if it were a button I could have in the tool bar next to the back button? Have you come across this request yet and/or have any suggestions on this?
Thanks much,
John
Hi John, could you explain “if it were a button I could have in the tool bar next to the back button?”
Well I have a universal app, using storyboards, with 9 or 10 View Controllers. The real problem Im trying to solve is that when a user is on an iPad and logs into the database on our server, has to be able to use the web form from the Drupal front end, which includes attaching images or video. For example we have teachers that log in and complete a daily report for each child that is sent to the parents within the app. However, the buttons for “upload” are greyed out when accessing from an iOS device. When you fill out a daily report on a PC or MAC, it works fine. So what would be great is if I could somehow put in a toolbar or something, versus sitting on its own View Controller, where it would give the user the ability to attach a photo to a web form.
Am I close, at least on the right track, or climbing the wrong hill?
Thank you,
John
John, I would go down the path of placing the code in its own view controller vs toolbar. Once you get past the Drupal session handling, I think you’ll find it an easier approach.
Hi Mike (or anybody else who has succeeded in using MKNetworkKit)
I am having a bit of trouble following this. I am using XCode 4.2 on Snow Leopard
I am trying to evaluate using MKNetworkKit to replace some hairy network code I wrote a year or so ago….
I used GitHub to download MKNetworkKit to my documents folder.
I built MKNetworkKit-IOS
Then….
I started by creating a new workspace (Uploader) and then a new project (Upload) as a single view application using storyboards. The project is in Desktop/Xcode Projects/Upload.
I then dragged the MKNetworkKit subfolder (i.e. the one that contains Reachability & Categories) to the project
copying the files across
I then dropped into Finder and removed the two unwanted files (NSAlert+…..h/m) and cleaned the project.
Then I modified Upload-Prefix.pch
#ifdef __OBJC__
#import
#import
#import “MKNetworkKit.h”
#endif
Then I tried to build it and I get an error “‘MKNetworkKit.h’ file not found”
Now I am pretty sure that I am missing something pretty simple but cannot figure out what. I am pretty sure that if I was supposed to change project settings somebody would have mentioned it…..
Any idea what my stupid error is?
can you give me exact backend php code , because i new to php, i don’t understand how can i write post.php code.
Needed to create you this little bit of note in order to give many thanks again over the marvelous guidelines you have shared on this website. It is seriously open-handed with you to allow extensively precisely what a few people would have offered for sale for an electronic book to generate some bucks for themselves, principally since you might well have tried it in the event you wanted. The ideas also acted to become great way to fully grasp other people have a similar desire just like my very own to realize a great deal more regarding this issue. I am sure there are numerous more pleasant moments up front for many who examine your blog post.
Great tutorial but I can find any working PHP script to handle the upload on the server. Somebody got it working?
Thanks!
Tom and Nizam, here’s a very, very basic PHP script that will handle the POST from the Xcode project. Let me warn you by stating that you should NOT use this script in production without serious modifications. Because I don’t know exactly what you’re trying to upload and how you’re handling security, I couldn’t incorporate these features. You’ll need to add file validation and authorization logic prior to using this script in the real world.
To get the script working, point the $uploaddir to your upload directory. Make sure that the upload directory is writeable by the web server user. That’s it!
Thank you Mike, that did the job for me!
Important note for other developers: Your fileName output in Xcode must contain a extension like ‘.png’. The posttestserver.com handles the post output as text but you wanna save it on your server as a image file.
Hey, thanks for the tutorial. I’m a complete beginner and i have one problem in the server URL. Could you give me your complete URL when uploading the file in this app?
my URL is “http://localhost:8888/tyego/appcon/try_upload” can you tell me how to put that in your code?
Thanks in advance!
Ty, the complete URL of the POST is http://posttestserver.com/post.php. The engine is initialized with the host name “posttestserver.com” and then we’re setting the path during the operation. Check out the code snippet within the blog post to see more details.
hey Mike, thanks for the quick reply.
I was trying on a localserver, but no luck. now i moved to my online server. but still no luck. i used codeigniter, but because i was failing all the time, i changed it to the server code you posted here. But still my image cant be uploaded.
i’ve made sure that the folder is accessible.
here is my code
self.flUploadEngine = [[fileUploadEngine alloc] initWithHostName:@”www.tyegah.com” customHeaderFields:nil];
NSMutableDictionary *postParams = [NSMutableDictionary dictionaryWithObjectsAndKeys:
@"kitten.jpg",@"filename",
nil];
self.flOperation = [self.flUploadEngine postDataToServer:postParams path:@"/upload2.php"];
[self.flOperation addData:image forKey:@"file" mimeType:@"image/jpeg" fileName:@"kitten.jpg"];
could you tell me what could be wrong in that code?
I’d be real glad if you could help.
Cheers!
What errors are you receiving? There should be some evidence server side within the web server logs. Your code looks ok but not sure why you’re including the file name within the postParams dictionary. The file name is already associated with the file within the addData method on the operation.
Hi Mike i’m new to app’s so apologies for my lack of knowledge.
I’ve been asked to help build an app that allows a user to add images then view them in order or as part of a calendar.
So my question is: If i want to make an app like this do i need to create my own server?
Where are the images stored at the moment in your app? And how would you reference them?
Joe, you’ll need your own server to create an app like you’re describing. If all you need is file storage, check out Amazon S3 or Rackspace Cloud Files.
thank you ! work like a charm…
But, :)
how i can take and send 2 photos in same view with your exemple ?
JPhi, you’d take the same approach as the code mentioned except you’ll need to handle the selection of one more photo. One way of doing this is to add some new iVars for the photos (you could go with an array if you so choose), set the variables within imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info and then call the addData method again to add the second photo to the request.
However hard I try, I just can’t do it.
Have you an example
Unfortunately I don’t. If I find the time, I might write another blog post about uploading multiple images at once.
Thanks for this tutorial, the code works very well for uploading images. But how about uploading a video after picking from library? I tried and it stopped at the compression:
NSData *movData = UIImageJPEGRepresentation([info objectForKey:UIImagePickerControllerOriginalImage], 0.1);
Easy to understand why the compression doesn’t work. The question is what method I should use for compressing video?
Thanks for your help!
Quyen, check out this example from stackoverflow http://stackoverflow.com/a/5853354
Not a problem mike,
i’ve found the solution…
A gift for you :)
A part of my code who works perfectly :))
//Déclaration du selecteur
int butSel = 0;
// Action reliée à mon 1er bouton et donc ma première photo :)
UIImagePickerControllerSourceTypePhotoLibrairy – - – :)
- (IBAction)uploadPhoto:(id)sender {
butSel = 1;
{
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
imagePicker.delegate = self;
imagePicker.allowsEditing = NO;
[self presentViewController:imagePicker animated:YES completion:nil];
}
else {
UIAlertView *alert;
alert = [[UIAlertView alloc] initWithTitle:@”Erreur”
message:@”Cet appareil ne prends pas de photos.”
delegate:self cancelButtonTitle:@”Ok”
otherButtonTitles:nil];
[alert show];
}
}
}
// Fin de l’action
/// Action reliée à mon 2nd bouton et donc ma seconde photo :)
- (IBAction)uploadPhoto2:(id)sender {
butSel = 2;
{
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
UIImagePickerController *imagePicker2 = [[UIImagePickerController alloc] init];
imagePicker2.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
imagePicker2.delegate = self;
imagePicker2.allowsEditing = NO;
[self presentViewController:imagePicker2 animated:YES completion:nil];
}
else {
UIAlertView *alert;
alert = [[UIAlertView alloc] initWithTitle:@”Erreur”
message:@”Cet appareil ne prends pas de photos.”
delegate:self cancelButtonTitle:@”Ok”
otherButtonTitles:nil];
[alert show];
}
}
}
// Fin de l’action
// Début de ma routine pour transferer sur le serveur web
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
//Passage 1ère photo
if(butSel==1){
[self dismissViewControllerAnimated:YES completion:nil];
NSData *image = UIImageJPEGRepresentation([info objectForKey:UIImagePickerControllerOriginalImage], 0.1);
//Affichage dans la UIImageView
imgPrint.image = [info objectForKey:UIImagePickerControllerOriginalImage];
//Definition du serveur pour le passage de la 1ère photo
self.flUploadEngine = [[fileUploadEngine alloc] initWithHostName:@”localhost:8888/appios” customHeaderFields:nil];
NSMutableDictionary *postParams = [NSMutableDictionary dictionaryWithObjectsAndKeys:
_uuidValue, @"uuid",
nil];
self.flOperation = [self.flUploadEngine postDataToServer:postParams path:@"/post.php"];
[self.flOperation addData:image forKey:@"userfl" mimeType:@"image/jpeg" fileName:@".photo1.jpg"];
[self.flOperation addCompletionHandler:^(MKNetworkOperation* operation) {
NSLog(@"%@", [operation responseString]);
}
errorHandler:^(MKNetworkOperation *errorOp, NSError* error) {
NSLog(@”%@”, error);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@”Erreur”
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:@”Ok”
otherButtonTitles:nil];
[alert show];
}];
[self.flUploadEngine enqueueOperation:self.flOperation ];
}
//Passage 2nd photo
if(butSel==2){
[self dismissViewControllerAnimated:YES completion:nil];
NSData *image = UIImageJPEGRepresentation([info objectForKey:UIImagePickerControllerOriginalImage], 0.1);
//Affichage dans la UIImageView
imgPrint2.image = [info objectForKey:UIImagePickerControllerOriginalImage];
//Definition du serveur pour le passage de la 2nd photo
self.flUploadEngine = [[fileUploadEngine alloc] initWithHostName:@”localhost:8888/appios” customHeaderFields:nil];
//Passage de mes variables texte de la 1ère et 2nd View sur la méthode withObjectsAndKeys
NSMutableDictionary *postParams2 = [NSMutableDictionary dictionaryWithObjectsAndKeys:
_uuidValue, @"uuid",
nil];
self.flOperation = [self.flUploadEngine postDataToServer:postParams2 path:@"/post.php"];
[self.flOperation addData:image forKey:@"userfl" mimeType:@"image/jpeg" fileName:@".photo2.jpg"];
[self.flOperation addCompletionHandler:^(MKNetworkOperation* operation) {
NSLog(@"%@", [operation responseString]);
/*
This is where you handle a successful 200 response
*/
}
errorHandler:^(MKNetworkOperation *errorOp, NSError* error) {
NSLog(@”%@”, error);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@”Erreur”
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:@”Ok”
otherButtonTitles:nil];
[alert show];
}];
[self.flUploadEngine enqueueOperation:self.flOperation ];
}
}
It’s a great sample and helped me make progress in my app
Thanks
Shimon wiener
Hi, first of all, congratulations on your kit. If I get it to work will do all I’ve been doing manually in a very professional way.
Now. I want to try the freezing option. I’m only adding [op setFreezable:YES]; But I don’t get the requests that i tried to post while the WiFi / 3G signal was down to be resent after it’s on again.
I would much appreciate your guidance on this.
Roberto
Thank you so much! yo save me!
God blesss you!
Rafa