return data from AFHTTPRequestOperation? - objective-c

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)
}];];

Related

AFNetworking 2.5.4 sending file with PATCH request

Using AFNetworking for communication between REST API and my application I ran into a strange behaviour wenn trying to upload an image with PATCH request.
I use following code:
- (void) uploadImage: (UIImage *)image {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = #{};
AFHTTPRequestSerializer *requestSerializer = [manager requestSerializer];
NSError *e = nil;
NSMutableURLRequest *request = [requestSerializer multipartFormRequestWithMethod:#"PATCH"
URLString:requestString
parameters:parameters
constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:UIImagePNGRepresentation(image)
name:#"image"
fileName:#"image.png"
mimeType:#"image/png"];
} error:&e];
[manager HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog("OK");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog("FAILED");
}];
}
Neither success not failed block of operation will be reached.
Wenn I change the request method to POST everything works fine, but the Server accepts only PATCH method for this case.
Am I doing something wrong?
I finally found a solution for my question:
- (void)uploadImage:(UIImage *)image
withSuccess:(SomeSuccessBlock)success
failure:(SomeFailureBlock)failure {
NSString *requestString = "Some url";
NSError *e = nil;
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
AFHTTPRequestSerializer *requestSerializer = [manager requestSerializer];
NSMutableURLRequest *request = [requestSerializer multipartFormRequestWithMethod:#"POST" URLString:requestString parameters:#{}
constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:UIImagePNGRepresentation(image)
name:#"user[avatar]"
fileName:#"avatar.png"
mimeType:#"image/png"];
} error:&e];
if (e && failure) {
failure(e);
return;
}
[request setHTTPMethod:#"PATCH"];
[request setValue:#"PATCH" forHTTPHeaderField:#"X-HTTP-Method-Override"];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if (success) {
success();
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (failure) {
failure(error);
}
}];
[operation start];
}

asynchronous function doesn't return data

I wrote a function to fetch an NSDictionary from a URL.
[Data loadFromAPI:#"http://example.com/api" withSuccess:^(id data) {
NSMutableDictionary *result = (NSDictionary *)data;
CLS_LOG(#"result: %#", result);
} failure:^(NSError *error) {
CLS_LOG(#"Error: %#", error);
}];
The function it calls is the one below:
typedef void (^Success)(id data);
typedef void (^Failure)(NSError *error);
+ (void)loadFromAPI:(NSString *)apiURL withSuccess:(Success)success failure:(Failure)failure {
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:apiURL]];
NSMutableURLRequest *mutableRequest = [request mutableCopy];
request = [mutableRequest copy];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [JSONResponseSerializerWithData serializer];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSArray *jsonArray = (NSArray *)responseObject ;
NSDictionary *result = [NSDictionary dictionaryWithObjectsAndKeys:
[self now], #"time",
jsonArray, #"response",
nil];
CLS_LOG(#"Result is: %#", result);
success(result);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
failure?failure(error):nil;
}];
[operationQueue setMaxConcurrentOperationCount:1];
[operationQueue addOperations:#[operation] waitUntilFinished:NO];
}
Inside the function CLS_LOG(#"Result is: %#", result); returns the data returned. However, where I call the function CLS_LOG(#"result: %#", result); returns null. What am I doing wrong?
As it turns out [self now] returned null, so the NSDictionary wasn't being set properly.
The problem is
NSMutableDictionary *result = (NSDictionary *)data;
you cant directly do that, i wonder why you dont have a warning for that..
NSMutableDictionary *result = [[NSMutableDictionary alloc] initWithDictionary:(NSDictionary *)data];
will probably solve the problem...

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];
}

Can't get HTML code AFNetworking 2.0

I tried to make GET HTTP response. I need to get the html code for the subsequent parsing, but responseObject is nil.
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:#"text/html"];
[manager GET:#"http://www.example.com/" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSError *error;
HTMLParser *parser = [[HTMLParser alloc] initWithString:responseObject error:&error];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
For get html code we will need to build a custom response serializer to decode the NSData response from the web server into a NSString. We will need to subclass AFHTTPResponseSerializer and implement the following method:
- (id)responseObjectForResponse:(NSURLResponse *)response
data:(NSData *)data
error:(NSError *__autoreleasing *)error
{
return [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
}
Why for example you have not use this solution below instead of subcalssing. It does the same thing, but you don't need to create additional files, just for overload one method.
So you can just add encoding your responseObjet in the block for example, and it will work as well. I am using POST in my example but it should work with GET in the same way but without parameters, but idea of the just conversation.
+ (void)makeRequestWithParams:(NSDictionary *)params
success:(OperationCompletionBlock)success
failure:(OperationCompletionBlock)failure
{
NSString *path = #"http://www.example.com/";
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFCompoundResponseSerializer serializer];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:#"text/html"];
[manager POST:path parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSString* encodedString = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
NSLog(#"%#", encodedString);
success(nil);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
failure(nil);
}];
}

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];