AFNetworking: success and failure blocks not called!! (POST to mysql backend) - objective-c

I am still trying to get a hang of objective-c and AFNetworking. I am doing a POST (through UI button) on mysql backend which returns a json response. I can see the download progress, but my success and failure blocks are never called. Code snippet below. I only see 1 and 4 printed out.
NSMutableURLRequest *apiRequest = [self multipartFormRequestWithMethod:#"POST" path:kAPIPath parameters:params constructingBodyWithBlock:^(id <AFMultipartFormData>formData) {
NSLog(#"Success in calling");
}];
AFHTTPRequestOperation* operation = [[AFJSONRequestOperation alloc] initWithRequest: apiRequest];
NSLog(#"1");
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
//success!
NSLog(#"Response: %#", [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding]);
NSLog(#"2");
completionBlock(responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
//failure :(
NSLog(#"3");
completionBlock([NSDictionary dictionaryWithObject:[error localizedDescription] forKey:#"error"]);
}];
});
NSLog(#"4");
[operation start];
[operation setDownloadProgressBlock:^( NSUInteger bytesRead , long long totalBytesRead , long long totalBytesExpectedToRead )
{
NSLog(#"%lld of %lld", totalBytesRead, totalBytesExpectedToRead);
}
];

Related

AFNetworking 1.x to 3.x migration for NSURLSessionTask?

I have a old project which is not working in iOS 9. I've read official documentation on AFNetworking and completed most of the migration.
NetworkManager:
_requestManager = [[AFHTTPSessionManager alloc]initWithBaseURL:[NSURL URLWithString:baseURL ]];
//here we can set the request header as the access token once we have logged in.
AFHTTPRequestSerializer *requestSerializer = [AFHTTPRequestSerializer serializer];
AFHTTPResponseSerializer *responseSerializer = [AFHTTPResponseSerializer serializer];
[_requestManager setRequestSerializer:requestSerializer];
[_requestManager setResponseSerializer:responseSerializer];
Earlier Version:
// 2. Create an `NSMutableURLRequest`.
NSMutableURLRequest *request =
[[NetworkManager sharedInstance].requestManager.requestSerializer multipartFormRequestWithMethod:#"POST" URLString:fullPath
parameters:nil
constructingBodyWithBlock: ^(id <AFMultipartFormData> formData) {
NSString *fileName = [NSString stringWithFormat:#"%#.caf", theAudioItem.media_item_name];
[formData appendPartWithFileData:audioData name:theAudioItem.media_item_name fileName:fileName mimeType:#"audio/caf"];
}];
// 3. Create and use `AFHTTPRequestOperationManager` to create an `AFHTTPRequestOperation` from the `NSMutableURLRequest` that we just created.
AFHTTPRequestOperation *operation =
[[NetworkManager sharedInstance].requestManager HTTPRequestOperationWithRequest:request
success: ^(AFHTTPRequestOperation *operation, id responseObject) {
result(YES, #"");
} failure: ^(AFHTTPRequestOperation *operation, NSError *error) {
if (operation.responseData) {
NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:operation.responseData options:NSJSONReadingMutableContainers error:nil];
result(NO, [responseDict valueForKey:#"Message"]);
[self deleteTmpFilesFromParts:formParts];
} else {
result(NO, [NSString stringWithFormat:#"Failed to upload media to %#!", gallery.gallery_name]);
[self deleteTmpFilesFromParts:formParts];
}
result(NO, errorMessage);
}];
// 4. Set the progress block of the operation.
[operation setUploadProgressBlock: ^(NSUInteger __unused bytesWritten,
long long totalBytesWritten,
long long totalBytesExpectedToWrite) {
DLog(#"progress is %i %lld %lld", bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
progress((float)totalBytesWritten / (float)totalBytesExpectedToWrite);
}];
// 5. Begin!
[operation start];
Converted Response: ( updated with comments what gives errors )
//No visible #interface for 'AFHTTPRequestSerializer<AFURLRequestSerialization>' declares the selector 'multipartFormRequestWithMethod:URLString:parameters:constructingBodyWithBlock:'
NSMutableURLRequest *request =
[[NetworkManager sharedInstance].requestManager.requestSerializer multipartFormRequestWithMethod:#"POST" URLString:fullPath parameters:nil
constructingBodyWithBlock: ^(id <AFMultipartFormData> formData) {
NSString *fileName = [NSString stringWithFormat:#"%#.caf", theAudioItem.media_item_name];
[formData appendPartWithFileData:audioData name:theAudioItem.media_item_name fileName:fileName mimeType:#"audio/caf"];
}];
// 3. Create and use `AFHTTPRequestOperationManager` to create an `AFHTTPRequestOperation` from the `NSMutableURLRequest` that we just created.
//No visible #interface for 'AFHTTPSessionManager' declares the selector 'HTTPRequestOperationWithRequest:success:failure:'
NSURLSessionTask *operation =
[[NetworkManager sharedInstance].requestManager HTTPRequestOperationWithRequest:request
success: ^(NSURLSessionTask *operation, id responseObject) {
result(YES, #"");
} failure: ^(NSURLSessionTask *operation, NSError *error) {
//Error for operation doesn't have responseData
if (operation.responseData) {
NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:operation.responseData options:NSJSONReadingMutableContainers error:nil];
result(NO, [responseDict valueForKey:#"Message"]);
[self deleteTmpFilesFromParts:formParts];
} else {
result(NO, [NSString stringWithFormat:#"Failed to upload media to %#!", gallery.gallery_name]);
[self deleteTmpFilesFromParts:formParts];
}
// get the response
result(NO, errorMessage);
}];
// 4. Set the progress block of the operation.
//No visible #interface for 'NSURLSessionTask' declares the selector 'setUploadProgressBlock:'
[operation setUploadProgressBlock: ^(NSUInteger __unused bytesWritten,
long long totalBytesWritten,
long long totalBytesExpectedToWrite) {
DLog(#"progress is %i %lld %lld", bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
progress((float)totalBytesWritten / (float)totalBytesExpectedToWrite);
}];
// 5. Begin!
//No visible #interface for 'NSURLSessionTask' declares the selector 'start'
[operation start];
The equivalent code for AFHTTPSessionManager is simply:
NSURLSessionTask *task = [[[NetworkManager sharedInstance] requestManager] POST:fullPath parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) {
NSString *fileName = [NSString stringWithFormat:#"%#.caf", theAudioItem.media_item_name];
[formData appendPartWithFileData:audioData name:theAudioItem.media_item_name fileName:fileName mimeType:#"audio/caf"];
} progress:^(NSProgress * _Nonnull uploadProgress) {
NSLog(#"%.3f", uploadProgress.fractionCompleted);
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
// success
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
// failure
// if you need to process the `NSData` associated with this error (if any), you'd do:
NSData *data = error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey];
if (data) { ... }
}];
This features two major changes from your v1.x code: First, with 2.x they introduced GET/POST/etc. methods that saved you from manually starting the operation (or adding it to your own queue). Second, with 3.x, they retired NSOperation framework of AFHTTPRequestOperationManager, and now use AFHTTPSessionManager class, where GET/POST/etc. don't return an NSOperation subclass, but rather a NSURLSessionTask reference.

return data from AFHTTPRequestOperation?

I'm moving my app code to an MVC model and so I created a method to retrieve some data from an API.
+ (NSMutableArray *)loadFromFeed {
NSString *feed = #"https://api.test.com";
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:feedUrl]];
request = [mutableRequest copy];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [JSONResponseSerializerWithData serializer];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSArray *jsonArray = (NSArray *)[responseObject objectForKey:#"items"];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
CLS_LOG(#"Error");
}];
}
Now, ideally, I'd like to return jsonArray as part of this method. However, since AFHTTPRequestOperation is asynchronous, I don't know how to solve this and still be able to call [Data loadFromFeed]; anywhere in the app. How can I do this?
You could pass two block named success and failure to loadFromFeed ,
and then call the two block from your setCompletionBlockWithSuccess success and failure block, passing jsonArray to the success block:
typedef void (^Success)(id data);
typedef void (^Failure)(NSError *error);
- (void)loadFromFeed:(Success)success failure:(Failure)failure;
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSArray *jsonArray = (NSArray *)[responseObject objectForKey:#"items"];
success?success(jsonArray):nil;
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
failure?failure(error):nil;
}];
then use in this way:
[Data loadFromFeed:^(id data) {
NSLog(#"%#",data)
} failure:^(NSError *error) {
NSLog(#"%#",error)
}];];

Creating dependencies between operations when using AFHTTPRequestOperation

I'm working with AFNetworking (2.4.1) in a mac application. I'm hoping to add my own block operation that is for after completion of all of the other operations (which are AFHTTPRequestOperation). I have tried adding dependencies between the completionOperation and the others, but the completionOperation block still executes before the others have completed with success or failure.
A cut down version of the code that illustrates the basics is below. Is anyone able to suggest how to make this work? Thanks.
AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] init];
NSBlockOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(#"All operations complete");
}];
NSMutableURLRequest *request1 = [[AFHTTPRequestSerializer serializer] requestWithMethod:#"GET" URLString:[[NSURL URLWithString:#"https://api.parse.com/1/classes/SomeClass"] absoluteString] parameters:nil error:nil];
AFHTTPRequestOperation *operation1 = [manager HTTPRequestOperationWithRequest:request1 success:
^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(#"operation 1 success");
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"operation 1 failure");
}];
NSMutableURLRequest *request2 = [[AFHTTPRequestSerializer serializer] requestWithMethod:#"GET" URLString:[[NSURL URLWithString:#"https://api.parse.com/1/classes/OtherClass"] absoluteString] parameters:nil error:nil];
AFHTTPRequestOperation *operation2 = [manager HTTPRequestOperationWithRequest:request2 success:
^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(#"operation 2 success");
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"operation 2 failure");
}];
[completionOperation addDependency:operation1];
[completionOperation addDependency:operation2];
[manager.operationQueue addOperation:operation1];
[manager.operationQueue addOperation:operation2];
[manager.operationQueue addOperation:completionOperation];
- (void) test3:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
// block 1
NSString *string = [NSString stringWithFormat:#"%#weather.php?format=json", BaseURLString];
NSURL *urll = [NSURL URLWithString:string];
NSURLRequest *request = [NSURLRequest requestWithURL:urll];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"OPERATION 1 %#",responseObject );
test_Sync = #"done";
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
test_Sync = #"faile"; }];
//block 2
NSString *string2 = [NSString stringWithFormat:#"%#weather.php?format=json", BaseURLString];
NSURL *urll2 = [NSURL URLWithString:string2];
NSURLRequest *request2 = [NSURLRequest requestWithURL:urll2];
AFHTTPRequestOperation *operation2 = [[AFHTTPRequestOperation alloc] initWithRequest:request2];
[operation2 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation2, id responseObject) {
// Print the response body in text
NSLog(#"Response: OPERATION 2 %#", [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding]);
} failure:^(AFHTTPRequestOperation *operation2, NSError *error) {
NSLog(#"Error: %#", error);
}];
// Add the operation to a queue
// It will start once added
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
// Make operation2 depend on operation1
[operation addDependency:operation2];
[operationQueue addOperations:#[operation, operation2] waitUntilFinished:YES];
}

i want to return data inside a block by using AFNetworking

I have a function using AFJSONRequestOperation, and I wish to return the result only after success. Could you point me in the right direction? I'm still a bit clueless with blocks and AFNetworking specifically.
It would have been better if you had posted your code
Using __block you can use variable inside block
__block NSString *msg;
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[hud hide:YES];
NSLog(#"Success %#", operation.responseString);
NSDictionary *message = [NSJSONSerialization JSONObjectWithData:[operation.responseString dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:nil];
NSLog(#"%#",message);
msg = message
ALERT(#"Posted", message[#"message"]);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error: %#", operation.responseString);
NSLog(#"%#",error);
}];
[operation start];

setDownloadProgressBlock in AFHTTPClient subclass

I created subclass of AFHTTPClient.
It works, but progress block return only final value (1.0). What should I change to get all the calculated values from setDownloadProgressBlock?
- (void)exploreVenuesCenter:(CLLocationCoordinate2D)coordinate inRadius:(int)radiusMeters success:(void (^)(NSArray *venues))success failure:(void (^)(NSError *error))failure progress:(void (^)(float progress))progress{
NSDictionary *parameters = #{#"limit": #"10",
#"client_id":kFoursquareClientID,
#"client_secret":kFoursquareClientSecret,
#"radius":#(radiusMeters).stringValue,
#"ll":[NSString stringWithFormat:#"%g,%g",coordinate.latitude, coordinate.longitude],
#"v":kFoursquareVersion};
NSMutableURLRequest *request = [self requestWithMethod:#"GET" path:#"venues/explore" parameters:parameters];
AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSArray *items = responseObject[#"response"][#"groups"][0][#"items"];
if (success)
{
success(items);
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) { if (failure) {
failure(error);
NSLog(error.localizedDescription);
} }];
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
//
float progressNo = ((float)totalBytesRead) / totalBytesExpectedToRead;
if (progress) {
progress(progressNo);
}
}];
[self enqueueHTTPRequestOperation:operation];
}