Error when uploading photo with AFNetworking - ios

I am uploading a photo using AFNetworking and I am getting the infamous "request body stream exhausted" error.
This is my code:
(_manager is a AFHTTPRequestOperationManager)
NSData *imageData = UIImageJPEGRepresentation(image, 1.0);
AFHTTPRequestOperation *operation = [_manager POST:address parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:imageData name:#"file" fileName:#"image.jpg" mimeType:#"image/jpeg"];
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Success!");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[operation setUploadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) {
NSLog(#"Written: %lld", totalBytesWritten);
}];
I get the error on both my iPhone 5S and my iPhone 4, both using wifi and 4G/3G. The issue is consistent and occurs every time, just when the upload is suppose to finish. The weird thing is that it use to work on these phones as well, but some days ago I suddenly started getting the error. Also, my colleague has no problems on his iPhone 5, both on wifi and 4G, running the same code. All phones run iOS 7.
I know that some people are getting this error when on 3G, and the solution in that situation is to use the throttleBandwidthWithPacketSize:(NSUInteger)numberOfBytes delay:(NSTimeInterval)delay method. However, this has had no affect in my case, and I get the error both on wifi and mobile.
I am able to perform the upload using curl from my computer which is on the same network.

I finally found a solution in this answer:
https://stackoverflow.com/a/21304062/569507
However, in stead of subclassing the AFHTTPRequestOperation as suggested, I simply made a category on it (or actually on its parent class AFURLConnectionOperation which implements the NSURLConnectionDataDelegate protocol) that contains the connection:needNewBodyStream method. This is all that is needed. The rest of my code remains unaltered.
AFURLConnectionOperation+Recover.h
#import "AFURLConnectionOperation.h"
#interface AFURLConnectionOperation (Recover)
- (NSInputStream *)connection:(NSURLConnection *)connection needNewBodyStream:(NSURLRequest *)request;
#end
AFURLConnectionOperation+Recover.m
#import "AFURLConnectionOperation+Recover.h"
#implementation AFURLConnectionOperation (Recover)
- (NSInputStream *)connection:(NSURLConnection *)connection needNewBodyStream:(NSURLRequest *)request
{
if ([request.HTTPBodyStream conformsToProtocol:#protocol(NSCopying)]) {
return [request.HTTPBodyStream copy];
}
return nil;
}
#end

NSData *imageData = UIImageJPEGRepresentation(img,1.0);
long long testBytes = 0;
for (int i=0; i<[arrImages count];i++)
{
UIImage *img =[arrImages objectAtIndex:i];
img=[AppManager scaleDownImage:img];
NSData *imageData1 = UIImageJPEGRepresentation(img,1.0);
testBytes +=[imageData1 length]+130;
}
AFHTTPRequestSerializer *serializer = [AFHTTPRequestSerializer serializer];
NSMutableURLRequest *request =
[serializer multipartFormRequestWithMethod:#"POST" URLString:[NSString stringWithFormat:#"%#%#",kBaseURL,kChallengeURL] parameters:aDic constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:imageData
name:kProfileImage
fileName:#"myimage.jPEG"
mimeType:#"image/jpeg"];
}
error:nil];
//
// [serializer multipartFormRequestWithMethod:#"POST" URLString:[NSString stringWithFormat:#"%#%#",kBaseURL,kChallengeURL]
// parameters:aDic
// constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
// [formData appendPartWithFileData:imageData
// name:#"attachment"
// fileName:#"myimage.jpg"
// mimeType:#"image/jpeg"];
// }];
// 3. Create and use `AFHTTPRequestOperationManager` to create an `AFHTTPRequestOperation` from the `NSMutableURLRequest` that we just created.
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
AFHTTPRequestOperation *operation =
[manager HTTPRequestOperationWithRequest:request
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
if ([[responseObject objectForKey:kStatus] intValue]==1)
{
NSArray *arrImages = [app.dicCreateChallangeDetail objectForKey:kProfileImage];
if ([arrImages count]==1)
{
[AppManager sharedManager].enCheckCreateService = eCreateWebserviceInStopped;
[[NSNotificationCenter defaultCenter]postNotificationName:kNotificationEnableTabBarButton object:nil userInfo:nil];
self.view.userInteractionEnabled = YES;
self.navigationItem.leftBarButtonItem.enabled = YES;
[self performSelector:#selector(goToHomeScreen) withObject:nil afterDelay:0.0];
}
else if ([arrImages count]>1)
{
[self uploadRestImages:[responseObject objectForKey:kChallengeId]];
}
}
else
{
[AppManager sharedManager].enCheckCreateService = eCreateWebserviceInStopped;
self.view.userInteractionEnabled = YES;
self.navigationItem.leftBarButtonItem.enabled = YES;
[Utils showAlertView:kAlertTitle message:[responseObject objectForKey:kMessage] delegate:nil cancelButtonTitle:kAlertBtnOK otherButtonTitles:nil];
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error){
//NSLog(#"Failure %#", error.description);
[AppManager sharedManager].enCheckCreateService = eCreateWebserviceInStopped;
self.view.userInteractionEnabled = YES;
self.navigationItem.leftBarButtonItem.enabled = YES;
[Utils showAlertView:kAlertTitle message:#"Failed. Try again" delegate:nil cancelButtonTitle:kAlertBtnOK otherButtonTitles:nil];
[[NSNotificationCenter defaultCenter]postNotificationName:kNotificationEnableTabBarButton object:nil userInfo:nil];
}];
// 4. Set the progress block of the operation.
[operation setUploadProgressBlock:^(NSUInteger __unused bytesWritten,
long long totalBytesWritten,
long long totalBytesExpectedToWrite) {
NSLog(#"Wrote %lld/%lld", totalBytesWritten, totalBytesExpectedToWrite);
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:#"%lld",totalBytesWritten],#"written",[NSString stringWithFormat:#"%lld",totalBytesExpectedToWrite],#"Totlal",nil];
[[NSNotificationCenter defaultCenter]postNotificationName:kNotificationRefreshHomePage object:dict userInfo:nil];
}];
// 5. Begin!
[operation start];

Related

Uploading pdf file from iphone

i have currently working on file handling application,where i have already completed image uploading using AFNetworking with multipart selection from camera as well as gallery.
but my question is how can i select a pdf file from device[iPhone]?
I would greatly appreciate it if you kindly give me some Answer. Thank You in Advanced.
Here is my image uploading code..
AFHTTPRequestOperationManager *man = [[AFHTTPRequestOperationManager alloc]init];
man.responseSerializer.acceptableContentTypes = [NSSet setWithObject:#"text/html"];
int i=0;
[self dispLoaderOnView:self.view loaderText:#"Loading.."];
for(i=0 ; i< selectedImages.count; i++)
{
NSData *imageData = UIImagePNGRepresentation([selectedImages objectAtIndex:i]);
AFHTTPRequestOperation *op = [man POST:FileUpload parameters:#{
#"queryid":#"37",
#"txtFilesQuery[]":imageData,
#"selFileType[]":self.textFieldChooseFile.text,
}
constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:imageData name:#"txtFilesQuery[]" fileName:[fileNamearray objectAtIndex:i] mimeType:#"image/png"];
}
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(#"Success: %# ***** %#", operation.description, operation.responseString);
if(i==selectedImages.count-1)
{
[self hideHUDLoader];
}
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"File Uploaded" message:#"Suucessfully.." delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
} failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"Error: %# ***** %#", operation.responseString, error);
}];
[op start];
}
NSData *imageData = UIImagePNGRepresentation([selectedImages objectAtIndex:i]);
replace this code by following line
NSData *myData = [NSData dataWithContentsOfFile:[selectedImages objectAtIndex:i]];
and
[formData appendPartWithFileData:imageData name:#"txtFilesQuery[]" fileName:[fileNamearray objectAtIndex:i] mimeType:#"image/png"];
Replace this code by following
[formData appendPartWithFileData:imageData name:#"txtFilesQuery[]" fileName:[fileNamearray objectAtIndex:i] mimeType:#"application/pdf"];
may this help u.......!!!!!
let me know if it help u.

Use result from asynchronous operation iOS

Hello I want to get result from asynchronous block from the class DataViewControllerto use it in the class MagazineViewControllerbut I don't get the value of returnedDataunless the ViewDidLoadmethod is called for the second time or more as the operation is asynchronous, I know that I have to implement a completion block and call it but I don't know exactly how to do it, this is my code, how can I edit it to give me the value returned in the setCompletionBlockWithSuccessblock and use it in other classes
DataViewController.m
- (void)getDataFromServer:(NSString *)urlString completion:(void (^)(AFHTTPRequestOperation *operation, id responseObject))completion {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSURLCredential *credential = [NSURLCredential credentialWithUser:userName password:Password persistence:NSURLCredentialPersistenceNone];
NSMutableURLRequest *request = [manager.requestSerializer requestWithMethod:#"GET" URLString:urlString parameters:nil];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCredential:credential];
[operation setResponseSerializer:[AFJSONResponseSerializer alloc]];
[operation setCompletionBlockWithSuccess:completion failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure: %#", error);
} ];
[manager.operationQueue addOperation:operation];
}
The MagazineViewController class (Where I want to use the returnedData)
#implementation MagazineViewController
void (^completion)(AFHTTPRequestOperation* , id) = ^(AFHTTPRequestOperation *operation, id responseObject){
returnedData = responseObject;};
- (void)viewDidLoad {
[super viewDidLoad];
DataViewController *dataViewController = [[DataViewController alloc] init];
[dataViewController getDataFromServer:#"http://firstluxe.com/api/search/search?query=vogue&language=1&output_format=JSON" completion:completion];
NSLog(#"returned %# ", returnedData); // here I get the value after the view controller is loaded for the second time or more
You should define completion inline. Your first NSLog statement is called before completion has been called, so the returnedData variable has not been set.
#implementation MagazineViewController
- (void)viewDidLoad {
[super viewDidLoad];
DataViewController *dataViewController = [[DataViewController alloc] init];
[dataViewController getDataFromServer:#"http://firstluxe.com/api/search/search?query=vogue&language=1&output_format=JSON"
completion:^ (AFHTTPRequestOperation *operation, id responseObject) {
returnedData = responseObject;
NSLog(#"returned %# ", returnedData);
}];
}
#end
[self getDataFromServer:#"API URL" completion:^(int *operation, id responseObject) {
// Result from async method here.
}];

Capture Upload Image Failed iOS

I m trying to upload image through AFNetworking.
Following is the way I try to save image in an array. Image uploading starts, but right after the 1.1% of upload it stops uploading without any error. No Idea what is happening.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[picker dismissViewControllerAnimated:YES completion:nil];
UIImage *chosenImage = info[UIImagePickerControllerOriginalImage];
NSData *imageData=UIImagePNGRepresentation(chosenImage);
ImageObject *imageObject=[[ImageObject alloc]init];
imageObject.image=chosenImage;
imageObject.imageData=imageData;
imageObject.imageUploadStatus=FALSE;
imageObject.isUploaded=FALSE;
[imageObject setDescription:#""];
[imageDataArray addObject:imageObject];
}
After this I upload image with Following method.
-(void)uploadPicturesAndVides:(NSMutableArray *)_list descriptions:(NSMutableArray *)_description categoryID:(NSString *)_catID categoryName:(NSString *)_categoryName index:(NSInteger)_index{
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
[manager.requestSerializer setValue:[SettingValues getRSFToken] forHTTPHeaderField:#"_csrf"];
[manager.requestSerializer setValue:#"USER_Agent_Value" forHTTPHeaderField:#"User-Agent"];
NSString *imageUrl;
imageUrl=[NSString stringWithFormat:#"%#/user/upload/photo",BASE_SERVER_ADDRESS];
NSMutableArray *tempArray=[[NSMutableArray alloc] init];
for (ImageObject *object in _list) {
[tempArray addObject:[object description]];
}
NSString *descriptions;
descriptions=[tempArray componentsJoinedByString:#","];
NSDictionary *parameters = #{#"descriptionImage":descriptions,#"subcategoryId":_catID,#"subcategoryName":_categoryName,#"_csrf": [SettingValues getRSFToken]};
AFHTTPRequestOperation *op = [manager POST:imageUrl parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
NSInteger count=_index;
for (ImageObject *object in _list) {
NSString *imageName = [NSString stringWithFormat:#"IMG00%zd.png",count];
[formData appendPartWithFileData:object.imageData name:#"files" fileName:imageName mimeType:#"image/png"];
}
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
[SettingValues setImageUploadStatus:TRUE];
[self uploadingRequestSuccessfulWithObject:responseObject reqestName:#"picture" index:_index];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
[op setUploadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) {
double percentDone = (double)totalBytesWritten / (double)totalBytesExpectedToWrite;
[self goBackTouploadingControllerWithProgressResult:percentDone index:_index];
}];
cancelManager=op;
[op start];
}
Following is the image and its progress stays here! no success no failure. :(
Problem is that code works when I upload image through Camera Roll, But when I capture image, it did not.
I put a NSLog(#"progress updated(percentDone) : %f", percentDone); in Progress Block and I found the following logs
2015-02-07 13:07:22.854 APP_Name[2069:60b] progress updated(percentDone) : 0.002105
2015-02-07 13:07:22.858 APP_Name[2069:60b] progress updated(percentDone) : 0.004210
2015-02-07 13:07:22.860 APP_Name[2069:60b] progress updated(percentDone) : 0.006315
2015-02-07 13:07:22.861 APP_Name[2069:60b] progress updated(percentDone) : 0.008413
and then every thing stops.
In Failure block I put following log
NSLog(#"Error: %# ***** %#", operation.responseString, error);
Never executed :(

AFNetworking Memory

Using AFNetworking to download files from a server. Here's the code:
self.networkQueue = [[[NSOperationQueue alloc] init] autorelease];
[networkQueue setMaxConcurrentOperationCount:3];
for(NSDictionary* fileDictionary in self.syncArray) {
#autoreleasepool {
if([[fileDictionary allKeys] containsObject:#"downloadZipURL"]) {
NSString* downloadPath = [fileDictionary objectForKey:#"downloadZipURL"];
downloadPath = [downloadPath stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
NSURLRequest *requestURL = [NSURLRequest requestWithURL:[NSURL URLWithString:downloadPath]];
NSString* localDestPath = [NSString stringWithFormat:#"%#/%#", [FileUtil userDocumentsDirectory], [downloadPath lastPathComponent]];
NSString* localTempPath = [NSString stringWithFormat:#"%#.tmp", localDestPath];
[(NSMutableDictionary*)fileDictionary setObject:localDestPath forKey:#"downloadDestination"];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:requestURL];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:localDestPath append:NO];
operation.userInfo = fileDictionary;
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if (networkQueue.operationCount == 0)
{
if(hasDownloadError || isCancellingSync) {
return ;
}
[self performSelectorInBackground:#selector(processAllFiles) withObject:nil];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
// [operation setDownloadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) {
// NSLog(#"Sent %lld of %lld bytes, %#", totalBytesWritten, totalBytesExpectedToWrite, localDestPath);
// float progress = (float)totalBytesWritten/(float)totalBytesExpectedToWrite;
// [(NSMutableDictionary*)operation.userInfo setObject:[NSString stringWithFormat:#"Downloading %.0f%%", progress*100] forKey:#"downloadStatus"];
// [(NSMutableDictionary*)operation.userInfo setObject:[NSNumber numberWithFloat:progress] forKey:#"downloadProgress"];
// [syncViewController onPermitUpdated];
// }];
[networkQueue addOperation:operation];
}
}
}
My problem is that once this code is run, memory slowly gets eaten up and never given back. Now, these can be large files, which is why I used the outputStream.
Any suggestions would be appreciated.
Off the top of my head - I see that you're not using ARC.
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:requestURL]
Are you releasing this operation somewhere?
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if (networkQueue.operationCount == 0)
{
if(hasDownloadError || isCancellingSync) {
return ;
}
[self performSelectorInBackground:#selector(processAllFiles) withObject:nil];
}
Here, you're using the networkQueue in the completionBlock and the block retains the networkQueue, you then add the operation to the networkQueue, which retains the operation, which leads to neither of them deallocating. Try making a weak variable of the networkQueue and use that in order to break the cycle.
If these don't work - run instruments and make a note of what objects remain in memory and when their reference count is changed.

AFNetworking POST Never Succeeding - Unexpected Behavior Occurring on Different Devices

I am currently developing an iOS app that allows a user to post a classified listing for other users to see. On all devices, that app hangs in a "O% Uploaded" SVProgressHUD for a while before displaying "Our server is temporarily unavailable. Please try again later.", which is what I have coded in the case of a Status Code 500 error from the server side. However, on the iOS simulator, everything works smoothly.
All other functionality involving network requests is working perfectly except for this, so it must have something to do with the actual upload process. I've posted the corresponding code below; if you require anything additional to help figure this out, please let me know.
Networking Code
- (IBAction)publishPressed:(UIBarButtonItem *)sender {
[SVProgressHUD showWithStatus:#"Loading..." maskType:SVProgressHUDMaskTypeBlack];
// Set the params for the API call in an NSMutableDictionary called mutableParams.
// Create the form request with the post parameters and image data to pass to the API.
NSMutableURLRequest *request = [[UAPIClient sharedClient] multipartFormRequestWithMethod:#"POST"
path:#"mobPost.php"
parameters:mutableParams
constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
if (self.imageHasBeenSet) {
[self.listingImageView.image fixOrientation];
NSData *imageData = UIImagePNGRepresentation(self.listingImageView.image);
[formData appendPartWithFileData:imageData name:#"userfile"
fileName:#"postImage.png" mimeType:#"image/png"];
}
}];
// Create the `AFJSONRequestOperation` from the form request, with appropriate success and failure blocks.
AFJSONRequestOperation *operation = [[AFJSONRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseJSON) {
if ([[responseJSON objectForKey:#"status"] intValue] == 1) {
dispatch_async(dispatch_get_main_queue(), ^{
[SVProgressHUD showSuccessWithStatus:#"Success!"];
});
// Pass a message back to the delegate so that the modal view controller
// can be dismissed successfully.
[self.delegate uCreateListingTableViewController:self didCreateListing:YES];
} else {
dispatch_async(dispatch_get_main_queue(), ^{
[SVProgressHUD showErrorWithStatus:#"Post failed. Please try again."];
});
NSLog(#"Status %#", [responseJSON objectForKey:#"status"]);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
dispatch_async(dispatch_get_main_queue(), ^{
[SVProgressHUD showErrorWithStatus:#"Our server is temporarily unavailable. Please try again later."];
});
}];
[operation setUploadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) {
dispatch_async(dispatch_get_main_queue(), ^{
[SVProgressHUD showSuccessWithStatus:[[NSString stringWithFormat:#"%lli", (totalBytesWritten / totalBytesExpectedToWrite)] stringByAppendingString:#"% Uploaded"]];
});
}];
[[UAPIClient sharedClient] enqueueHTTPRequestOperation:operation];
}
UAPIClient.m
#import "UAPIClient.h"
#import "AFJSONRequestOperation.h"
static NSString * const kUAPIBaseURLString = #"hiding string for privacy";
#implementation UAPIClient
+ (UAPIClient *)sharedClient {
static UAPIClient *_sharedClient;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedClient = [[UAPIClient alloc] initWithBaseURL:[NSURL URLWithString:kUAPIBaseURLString]];
});
return _sharedClient;
}
- (id)initWithBaseURL:(NSURL *)url {
self = [super initWithBaseURL:url];
if (self) {
[self registerHTTPOperationClass:[AFJSONRequestOperation class]];
// Accept HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
[self setDefaultHeader:#"Accept" value:#"application/json"];
}
return self;
}
#end

Resources