File uploading example using AFNetworking (iOS Example)

afnetworking ios example

 

Today i would like to write an example of step by step guide to show  you how to upload a  photo and Photo Name using iOS AFNetworking library.

 

 

Why you should use AFNetworking Library

Working with low level API is really  a time consuming task. To make your work easier and much quicker, You can use AFNetworking library for your iOS or Mac OS X Projects, The library is well designed and fully tested. Apart from everything, AFNetworking is used by many applications in Appstore. I suggest you to use AFNetworking library for your next project.!

 

 

Webservice for the Photo uploading

I wrote a simple web service request handler using php. I have a confident that if your  client side code is working for this web service, It should work for other web services too. Don’t use this code in your production because we should write proper web service in order to use in production level applications.

 

<?php

 

<?phperror_reporting(E_ALL);

ini_set('display_errors', 'off'); //turn on if you want to see the server errors and notifications.

$target_dir = "uploads/";

$filename = $_POST['filename'];

$target_file = $target_dir . $filename;

if (file_exists($_FILES["fileToUpload"]["tmp_name"])) {

if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {

echo json_encode(array("message" => "Upload Success.!"));

} else {

echo json_encode(array("message" => "Upload Failed.!"));

}

} else {

echo json_encode(array("message" => "No Files Found.!"));

}

 

?>

 

 

I am passing two fields to the Webserive,

  1. File Name (Type : String).
  2. Image File (Type : File)

 

 

Test the Webservice using POSTMAN.

Postman is really a handy tool to test the web services. You can test the web service using their free tier. Download their PC Version or you can install Chrome plugin.  Download it and play now.!

 

 

 

 

Don’t forget to set content-type to “application/x-www-form-urlencoded” in headers section, when you test the web service via PostMan.

(I will write separate post for PostMan later.)

 

 

Create AfNetworking Example Application in Xcode 8.2

 

 

Now is the time to add the AFNetwork library to the project.

 

Add AFNetworking Library to the Project.

You can either add using any CocoaPods or Manual.  I will show you how to add the library manually. Download the Library files from GitHub.

 

To install Afnetwrking library, You can use Cocoa pads as well.

 

Open terminal and goto project directory.

 

pod init

 

New Pod file will be created in the project path. Your pod file should be like this

target 'AfNetowrkExample' do
# Uncomment the next line if you're using Swift or would like to use dynamic frameworks
# use_frameworks!

# Pods for AfNetowrkExample

pod 'AFNetworking', '~> 3.0'

target 'AfNetowrkExampleTests' do
inherit! :search_paths
# Pods for testing
end

end

 

Now install the the Cocoapods

pod install

 

Quit Xcode and Open Open “AfNetowrkExample.xcworkspace”  always because you are using cocoa pods

 

Thats all. you can utilize the AFNetworking library features in your application now onwards.

 

Design UI interface in XCode application

 

 

There will be 3 buttons and UIImageview components.

Buttons are

  1. Capture Image Button.
  2. Select Image Button.
  3. Upload image to the server button

 

Connect the buttons and UIImageview to the particular UIViewController class accordingly.

//  ViewController.h

 

#import <UIKit/UIKit.h>

#import "FileUtil.h"

@interface ViewController : UIViewController <UIImagePickerControllerDelegate>

@property (weak, nonatomic) IBOutlet UIButton *uploadBtn;

@property (weak, nonatomic) IBOutlet UIImageView *imageView;

- (IBAction)uploadimage:(id)sender;

- (IBAction)capturePhoto:(id)sender;

- (IBAction)selectPhoto:(id)sender;

@property UIImage* image;

@end

 

 

To connect button with View Controller please check the

 

Now implement the button actions and business logic in the UIViewController.m file

 

 

//  ViewController.m

#import "ViewController.h"

#import "AFNetworking.h"

@interface ViewController ()

@end

@implementation ViewController

//Server url for the file upload handling.

static NSString *ServerPath = @"https://appsgit.com/appsgit-service/fileupload.php";

- (void)viewDidLoad {

[super viewDidLoad];

// Do any additional setup after loading the view, typically from a nib.

}

- (void)didReceiveMemoryWarning {

[super didReceiveMemoryWarning];

// Dispose of any resources that can be recreated.

}

#pragma Upload Capture Photo Action method implementation.

- (IBAction)capturePhoto:(id)sender {

 

/*Check if the Device supports Camera feature. Camera feature is not available in Simulators. You can only select image in the simulator.

*/

if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {

 

UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"File Exist" message:@" No Camera found." preferredStyle: UIAlertControllerStyleAlert];

 

UIAlertAction *action = [UIAlertAction actionWithTitle:@"OKK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){

 

}];

 

[controller addAction:action];

 

[self presentViewController:controller animated:YES completion:nil];

 

return;

}

 

UIImagePickerController *picker = [[UIImagePickerController alloc] init];

picker.delegate = self;

picker.allowsEditing = YES;

picker.sourceType = UIImagePickerControllerSourceTypeCamera;

 

[self presentViewController:picker animated:true completion:nil];

}

#pragma Upload Select Photo Action method implementation.

- (IBAction)selectPhoto:(id)sender {

 

//Open Gallery to select an image.

UIImagePickerController *picker = [[UIImagePickerController alloc] init];

picker.delegate = self;

picker.allowsEditing = YES;

picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;

 

[self presentViewController:picker animated:YES completion:NULL];

}

#pragma Upload image button Action method implementation.

- (IBAction)uploadimage:(id)sender {

 

//You must select or capture image inorder to upload it to the server.

if (self.image == nil) {

 

UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"File Exist" message:@"Please select an image or Capture image using camera." preferredStyle: UIAlertControllerStyleAlert];

 

UIAlertAction *action = [UIAlertAction actionWithTitle:@"OKK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){

//anything to do...

NSLog(@"ok pressed...");

}];

 

[controller addAction:action];

 

[self presentViewController:controller animated:YES completion:nil];

 

return;

}

 

if (self.image != nil) {

 

//Save the image to device temp location and get the path.

NSString *path = [FileUtil saveImageTODocumentAndGetPath:self.image];

NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:path];

 

AFHTTPRequestSerializer *requestSerializer = [AFHTTPRequestSerializer serializer];

 

NSMutableURLRequest *request = [requestSerializer multipartFormRequestWithMethod:@"POST" URLString:ServerPath parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {

[formData appendPartWithFileURL:fileURL name:@"fileToUpload" fileName:@"fileiOS.jpg" mimeType:@"image/jpeg" error:nil];

 

NSData *fileNameconvertedToUTF8data = [@"my_file_name.jpg" dataUsingEncoding:NSUTF8StringEncoding];

 

[formData appendPartWithFormData:fileNameconvertedToUTF8data name:@"filename"];

} error:nil];

 

[request setTimeoutInterval:20000];

 

AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];

 

manager.responseSerializer = [AFHTTPResponseSerializer serializer];

 

manager.securityPolicy.allowInvalidCertificates = YES; // not recommended for production

manager.securityPolicy.validatesDomainName = NO;

 

[requestSerializer setValue:@"multipart/form-data" forHTTPHeaderField:@"content-type"];

 

NSURLSessionUploadTask *uploadTask;

uploadTask = [manager

uploadTaskWithStreamedRequest:request

progress:^(NSProgress * _Nonnull uploadProgress) {

// This is not called back on the main queue.

// You are responsible for dispatching to the main queue for UI updates

dispatch_async(dispatch_get_main_queue(), ^{

//Update the progress view

NSLog(@"Running....");

});

}

completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {

if (error) {

NSLog(@"Error: %@", error);

} else {

 

NSString *responseMessage = [NSString stringWithUTF8String:[responseObject bytes]];

 

UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"File Upload" message:responseMessage preferredStyle: UIAlertControllerStyleAlert];

 

UIAlertAction *action = [UIAlertAction actionWithTitle:@"OKK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){

//anything to do...

NSLog(@"ok button pressed...");

}];

 

[controller addAction:action];

 

[self presentViewController:controller animated:YES completion:nil];

}

}];

 

[uploadTask resume];

 

}

}

#pragma Image Picker Delegate methods.

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {

 

UIImage *chosenImage = info[UIImagePickerControllerOriginalImage];

 

self.image = [self imageWithImage:chosenImage scaledToSize:CGSizeMake(500, 500)];

 

self.imageView.image = self.image;

 

[picker dismissViewControllerAnimated:YES completion:NULL];

 

}

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {

 

[picker dismissViewControllerAnimated:YES completion:NULL];

 

}

//Reduce the width and height of the image in order to reduce the size.

- (UIImage*)imageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize {

UIGraphicsBeginImageContext( newSize );

[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];

UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

return newImage;

}

@end

 

 

We have used FileUtil.h class for some utility methods. Lets look at the class

 

//  FileUtil.h

//  AfNetowrkExample

 

#import <Foundation/Foundation.h>

#import <UIKit/UIKit.h>

@interface FileUtil : NSObject

+(BOOL) fileExistsInProject:(NSString *)fileName;

+(NSString*) saveImageTODocumentAndGetPath: (UIImage *) image;

@end

 

 

//  FileUtil.m

 

#import "FileUtil.h"

@implementation FileUtil

+(BOOL) fileExistsInProject:(NSString *)fileName

{

NSFileManager *fileManager = [NSFileManager defaultManager];

NSString *fileInResourcesFolder = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:fileName];

return [fileManager fileExistsAtPath:fileInResourcesFolder];

}

+(NSString*) saveImageTODocumentAndGetPath: (UIImage *) image {

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,

NSUserDomainMask, YES);

NSString *documentsDirectory = [paths objectAtIndex:0];

NSString* path = [documentsDirectory stringByAppendingPathComponent:

@"test.png" ];

NSData* data = UIImagePNGRepresentation(image);

[data writeToFile:path atomically:YES];

 

return path;

}

@end

 

 

We are done with the classes.

 

If you try to run the application using simulator, You may receive following errors.

 

AfNetowrkExample[2080:51541] [Generic] Creating an image format with an unknown type is an error

AfNetowrkExample[2080:51983] App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.

AfNetowrkExample[2080:51541] Throw if there is any Error: Error Domain=NSURLErrorDomain Code=-1022 "The resource could not be loaded because the App Transport Security policy requires the use of a secure connection." UserInfo={NSUnderlyingError=0x61800024d9b0 {Error Domain=kCFErrorDomainCFNetwork Code=-1022 "(null)"},

NSLocalizedDescription=The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.}

 

You are missing “NSAppTransportSecurity” Key in info.plist

  1. Open Project info.plist file.
  2. Add a Key called NSAppTransportSecurity as a Dictionary.
  3. Add a Subkey called NSAllowsArbitraryLoads as Boolean and set its value to YES.

 

Try again. If you get the following error,

 

AfNetowrkExample[7587:519936] [access] This app has crashed because it attempted to access privacy-sensitive data without a usage description.  The app's Info.plist must contain an NSPhotoLibraryUsageDescription key with a string value explaining to the user how the app uses this data.

 

You are missing “NSPhotoLibraryUsageDescription”

You have to add the key to info.plist file. like below

 

 

Now  Run the application and select an image. You will see the selected image will be placed in the uiimageview.  If you press the upload image button you should receive an alert like below.

 

 

 

 

Possible errors and solutions.

 

 AfNetowrkExample[12515:489843] Throw if there is any Error: Error Domain=NSPOSIXErrorDomain Code=100 “Protocol error” UserInfo={_kCFStreamErrorCodeKey=100, _kCFStreamErrorDomainKey=1}

The above error mainly because of improper Content-Type.

 

AFHTTPRequestSerializer *requestSerializer = [AFHTTPRequestSerializer serializer];

[requestSerializer setValue:@"multipart/form-data" forHTTPHeaderField:@"content-type"];

 

Still error occured ?  Just remove the content type it and test it again.!

 

 


 

AfNetowrkExample[12681:495565] Throw if there is any Error: Error Domain=NSURLErrorDomain Code=-1200 “An SSL error has occurred and a secure connection to the server cannot be made.” UserInfo={_kCFStreamErrorCodeKey=-9802, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, NSUnderlyingError=0x610000058360 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 “(null)” UserInfo={_kCFStreamPropertySSLClientCertificateState=0, _kCFNetworkCFStreamSSLErrorOriginalValue=-9802, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802}}, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSErrorFailingURLKey=https://appsgit.com/appsgit-service/fileupload.php, NSErrorFailingURLStringKey=https://appsgit.com/appsgit-service/fileupload.php, _kCFStreamErrorDomainKey=3}

 

The solution for the above issue is

 

AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];

manager.securityPolicy.allowInvalidCertificates = YES; // not recommended for production

manager.securityPolicy.validatesDomainName = NO;

 

 


 

 

AfNetowrkExample[14629:591058] Error: Error Domain=com.alamofire.error.serialization.response Code=-1016 “Request failed: unacceptable content-type: text/html” UserInfo={com.alamofire.serialization.response.error.response=<NSHTTPURLResponse: 0x7c174a80> { URL: https://appsgit.com/appsgit-service/fileupload.php } { status code: 200, headers {

    “Content-Type” = “text/html; charset=UTF-8”;

    Date = “Wed, 11 Oct 2017 19:20:19 GMT”;

    Server = nginx;

    “host-header” = 192fc2e7e50945beb8231a492d6a8024;

} }, NSErrorFailingURLKey=https://appsgit.com/appsgit-service/fileupload.php, NSLocalizedDescription=Request failed: unacceptable content-type: text/html, com.alamofire.serialization.response.error.data=<7b226d65 73736167 65223a22 55706c6f 61642053 75636365 73732e21 227d>}

 

Solution for the above error is,

 

AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];

manager.responseSerializer = [AFHTTPResponseSerializer serializer];

 

 

 

Thats all folks. You can download the updated code from AppsGit GitHub account.

 

Please leave your comment.!

 

 

About Zumry

Zumry Mohamed

Self Taught iOS & Android Mobile Application Developer.

Article written by zumrywahid

Self Taught iOS & Android Mobile Application Developer.

This Article Has 2 Comments
  1. pragati Reply

    Hey I tried to run your project but It occures “NSLocalizedDescription=Request failed: unauthorized (401)}” these error. Can you please guide me?

Leave a Reply

Your email address will not be published. Required fields are marked *