I'm trying to upload multiple photos in background mode using AFNetworking and I managed to make it work.
The main problem I'm facing now is memory, which, while uploading more than 10 photos, runs out terminating my app.
What I'm doing is just firing all the uploads simultaneously as I've read in some answers on StackOverflow.
Now that this problem arises I'm wondering if I'm doing something wrong with memory management or if a better strategy would be to serialize the uploads, start the first one and when it terminates start the upload of the next in the handleEventsForBackgroundURLSession method.
Before changing completely the upload design I would like to hear from someone if it's a good alternative, as the majority of answers I've seen regarding this matter state that one should fire all the requests together.
Thank you
Create NSOperationQueue and add all your upload image operation to that queue. This queue will manage your system memory. Please refer below sample code.
NSOperationQueue *myQueue = [[NSOperationQueue alloc]init];
NSURLRequest *request = [[AFHTTPRequestSerializer serializer]
multipartFormRequestWithMethod:#"POST"
URLString:apiPostPhoto(singleton.userId, #"icon")
parameters:nil
constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
NSString *filepath = [[CustomFunctions getFilesPath] stringByAppendingPathComponent:#"icon.png"];
[formData appendPartWithFileURL:[NSURL fileURLWithPath:filepath] name:#"uploadicon" error:nil];
} error:nil
];
AFHTTPRequestOperation *operationUploadOne = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"uploadlogo:%#",operation.responseString);
[[NSUserDefaults standardUserDefaults]setObject:operation.responseString forKey:KEY_LOGO_TIMESTAMP];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"uploadlogo:%#",[error description]);
}];
[operation addObserver:self forKeyPath:#"isFinished" options:NSKeyValueObservingOptionNew context:nil];
[myQueue addOperation:operationUploadOne];
AFHTTPRequestOperation *operationUploadTwo = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
[myQueue addOperation: operationUploadTwo];
you can add more number of operation using this method.
[myQueue addOperation: operationUploadTwo];
Related
Handle single download via afnetworking is good my question is that how handle multiple click on different button then it call this method then process break previous.
it is bcoz suppose several button hit at time then it confuse to download. how handle multiple download in selector method,if in array of batch download then it's easy but through which how .
-(void)downloadimagefromserver:(UIButton *)sender
{
int index =(int) sender.tag;
historyclass *class1 = [messages objectAtIndex:index];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:arrayOfStringsfinal[1]]];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(#"success");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[operation start];
}
After few days of job I am not able to solve this issue, I really need your help because I am completely locked, I start to be crazy!!!!!!. I have a project in Objective c for iOS where I get data from my server to put in my application. I have some trouble to recover and save data from JSON.
I would like to use "id responseObject", and save and use the content in another area in my project. Each time I try to use the following method and use "id responseObject" outside of "setCompletionBlockWithSucess" the "id responseObject" is (null), how can I do ?
NSURL *URL = [NSURL URLWithString:#"…."];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request];
op.responseSerializer = [AFJSONResponseSerializer serializer];
[op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[[NSOperationQueue mainQueue] addOperation:op]
It sounds like you don't quite understand what scope is for variables. This project may be too advanced for you if that's the case. I urge you to read into scope + blocks to get a better understanding of what's going on.
What is happening is the setCompletionBlockWithSuccess is actually a block of code that gets executed if the URL request is a success. This means that responseObject is not immediately executed! It's being passed back some time after and you get access to it within setCompletionBlockWithSuccess. So that's why it's nil outside of the block.
To do what you're wanting is very simple. You need to read responseObject within the setCompletionBlockWithSuccess and set it to another variable that you have access to. Or you can immediately send it to another class to parse/save.
I haven't tested it, but I believe this should work with a simple JSON response. If not, use operation.responseString instead
NSString *jsonResponse;
NSURL *URL = [NSURL URLWithString:#"…."];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request];
op.responseSerializer = [AFJSONResponseSerializer serializer];
[op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
jsonResponse = responseObject;
}
...
I need to check the size of file from a URL. I get the file size perfectly when downloading file with AFNetworking.
AFHTTPRequestOperation *operation = [client HTTPRequestOperationWithRequest:request
success:^(AFHTTPRequestOperation *operation, id responseObject) {
// Success Callback
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// Failure Callback
}];
and get file size in another block
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
}];
But i need to check file size before initiating download request, so that i can prompt to user. I have also tried another method
NSURL *url = [NSURL URLWithString:#"http://lasp.colorado.edu/home/wp-content/uploads/2011/03/suncombo1.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
NSLog(#"original = %d", [data length]);
But it blocks the UI, coz it download all data to calculate its size.
Is there any way to check file size before downloading? Any help is appreciated.
If the server supports it you can make a request to just get the headers (HEAD, as opposed to GET) without the actual data payload and this should include the Content-Length.
If you can't do that then you need to start the download and use expectedContentLength of the NSURLResponse.
Basically, create an instance of NSMutableURLRequest and call setHTTPMethod: with the method parameter set to #"HEAD" (to replace the default which is GET). Then send that to the server as you currently request for the full set of data (same URL).
here is the code:
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:candidateURL];
[request setHTTPMethod:#"HEAD"];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(#"Content-lent: %lld", [operation.response expectedContentLength]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
I'm using AFNetworking to send a multipart form to a web-server, and i'm having some trouble with my AFHTTPRequestOperation. It's success and failure blocks are never called, after i start it.
Here is my code (a resume of it)
NSMutableURLRequest *request = [[ServerAPI sharedClient] multipartFormRequestWithMethod:#"POST" path:postUrl parameters:nil constructingBodyWithBlock: ^(id <AFMultipartFormData> formData) {
[formData appendPartWithFileData:picture.picture_data name:#"InputFile" fileName:picture.name mimeType:#"image/jpg"];
}];
AFHTTPRequestOperation *operation = [[ServerAPI sharedClient] HTTPRequestOperationWithRequest: request success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Success");
} failure: ^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure");
}];
[operation setUploadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
NSLog(#"%f", (totalBytesRead / (float) totalBytesExpectedToRead));
}];
[[ServerAPI sharedClient] enqueueHTTPRequestOperation:operation];
I can see the logs of the progress, but success and failure blocks are never called.
picture.picture_data is a NSData initialized with a UIImageJPEGRepresentation(image, 0.7)
ServerAPI is a subclass of AFHTTPClient, and sharedCliend is a singleton method.
Which are the reasons for AFNetworking don't call my blocks, not even with an proper error message?
Thank you all!
Edit
I do a get request with the same URL just before this one, and it works as usual. The URL i'm using is: part/_layouts/UploadEx.aspx?List=%7BD432BF97-7175-40C1-8E0D-27D8661CBC90%7D&RootFolder=%2Fpwa%2Fpart%2FLibrary&Source=http%3A%2F%2Fwww%2Emysite%2Ecom%2Fpwa%2Fpart%2FLibrary%2FForms%2FAllItems%2Easpx&IsDlg=1
In your code, check your postUrl . The BaseURL+postURL must be valid. Try upload image using normal web browser using URL BaseURL+postURL.
Edit
method HTTPRequestOperationWithRequest:success:failure: does not work for file uploading, but works for json/html fetching.
Try use
AFHTTPRequestOperation *operation = [[AFJSONRequestOperation alloc] initWithRequest:request];
[operation setUploadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
NSLog(#"%f", (totalBytesRead / (float) totalBytesExpectedToRead));
}];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Success");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure");
}];
[[ServerAPI sharedClient] enqueueHTTPRequestOperation:operation];
hopefully this is an easy question, tho, I cannot find any specific answers.
we've gone thru all the steps to update our enterprise app OTA. My question is, can I use AFNetworking to make the call? or what is the best way to call the link. (currently afnetworking is giving me errors but it may be something on our side.) I am using afnetworking exclusively, so would rather not change unless I have to.
thanks in advance
itms-services://?action=download-manifest&url=http://ourServer/Setup/manifest.plist
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:kiPADSetupLink]];
[request setTimeoutInterval:300];
NSLog(#"begin downloading app update");
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
// handle success
} failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
// handle error
} ];
[operation start];
No, you need the system to open that URL, you can't access it yourself. Use UIApplication's openURL: method.