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];
}
Related
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];
}
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)
}];];
I'm trying to learn AFNetworking so have written a simple block. I'm trying to retrieve & log the json from the site url below.
NSString *string =
#"http://transportapi.com/v3/uk/bus/stop/490012745J/live.json?api_key=6ee115459cbeccdb902b14d39b61330d&app_id=9deefeb1&group=route";
NSURL *url = [NSURL URLWithString:string];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSDictionary *mydict = (NSDictionary *)responseObject;
NSString *key;
for(key in mydict){
NSLog(#" key %#", key);
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"ERROR");
}];
But neither the success or the failure block is being called. Can someone point out what I've done wrong?
You're not actually firing the operation you need to add
[[NSOperationQueue mainQueue] addOperation:operation];
Im trying to post with an array as the post instead of a dictionary. However i get an error:
Incompatible pointer types sending NSMutableArray to parameter of type NSDictionary
Here is the code
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSMutableArray *parameters = #[#"foo", #"bar"];
[manager POST:#"http://example.com/resources.json" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
How can I post JUST the arrays contents?
Update:
This code works, but I would prefer to get the answer below working as its cleaner and af handles the serialization. Im guessing the request body is different, but how do i see what the body is?
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parameters
options:NSJSONWritingPrettyPrinted
error:&error];
NSString *body = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://example.com/resources.json"]
cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10];
[request setHTTPMethod:#"POST"];
[request setValue: #"application/json" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody: [body dataUsingEncoding:NSUTF8StringEncoding]];
AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request];
op.responseSerializer = [AFJSONResponseSerializer serializer];
[op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON responseObject: %# ",responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", [error localizedDescription]);
}];
[op start];
I am assuming you want foo and bar to be your parameters without any values? if so you will want to do something like this
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSMutableArray *parameters = #[#"foo", #"bar"];
NSDictionary *params = [[NSDictionary alloc] initWithObjects:#[[NSNull null], [NSNull null]] forKeys:parameters];
[manager POST:#"http://example.com/resources.json" parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
EDIT
Try adding
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
I'm trying to have my app load an HTML web page into a "responseObject" that I can later parse.
Here is my code:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:#"application/xhtml+xml"];
NSDictionary *parameters = #{#"ghinno": #"1151213"};
[manager GET:#"http://m.ghin.com/HLR.aspx" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"HTTP: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
...and this is the output. I should be seeing the html from the webpage. Can you help me understand what I am doing wrong?
Ah, the answer lies below...
Essentially, it was an encoding / decoding of the response object that was causing my issues. Here is the final solution: (notice the line beginning with "NSString)...
NSURL *URL = [NSURL URLWithString:#"http://m.ghin.com/HLR.aspx?ghinno=1151213"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSString *string = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
NSLog(#"%#", string);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[op start];