AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:#"http://aaa"
success:^(AFHTTPRequestOperation *operation, id responseJSON) {
...
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[[TWMessageBarManager sharedInstance]
showMessageWithTitle:#"Network connection failure"
description:#"Please check your network"
type:TWMessageBarMessageTypeError];
}];
Some block is constant, can be used repeatedly. For example here's failure block, How can I reuse this block for reduce the amount of code?
I hope it is a global reuse, rather than the current context, so I can store it as a property? Or get_method()?
Save the block to a variable, then you can pass that around:
void (^failureBlock)(AFHTTPRequestOperation *operation, NSError *error) = ^void(AFHTTPRequestOperation *operation, NSError *error) { /* write what you want */ };
void (^successBlock)(AFHTTPRequestOperation *operation, id responseJSON) = ^void(AFHTTPRequestOperation *operation, id responseJSON) { /* write what you want */ };
Then you can use it in further calls like this:
[manager GET:#"" success:successBlock failure: failureBlock];
Bonus: Check out this guide.
you can save it like a variable like so:
void(^blockname)(AFHTTPRequestOperation*, NSError*) = ^(AFHTTPRequestOperation *operation, NSError *error) {
[[TWMessageBarManager sharedInstance]
showMessageWithTitle:#"Network connection failure"
description:#"Please check your network"
type:TWMessageBarMessageTypeError];
}
then just put blockname for the failure parameter instead of the whole thing
Another approach, instead of reuse blocks, you should consider reuse the whole function
- (void)getURLPath:(NSString *)urlPath withSuccessBlock:(void (^)(id responseJSON))block {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:urlPath
success:^(AFHTTPRequestOperation *operation, id responseJSON) {
...
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[[TWMessageBarManager sharedInstance]
showMessageWithTitle:#"Network connection failure"
description:#"Please check your network"
type:TWMessageBarMessageTypeError];
}];
}
Related
I have the following code:
NSDictionary *parameters = #{#"parameter1":objectVariable1,#"parameter2":objectVariable2};
[MANAGER POST:#"http:www.myserver.com/somelink" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject)
{
//PROCESS RESPONSE
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
//PROCESS FAILURE
}];
In case of failure how do I retry this connection considering the objectVariable1 & objectVariable2 can change at any point (while the connection is sent to the server) thus the same post parameters as before must be sent.
Can the parameters be obtained from AFHTTPRequestOperation *operation in the error branch?
Just to be sure, for example, this can be the case:
- objectVariable1 = 1
- send connection with objectVariable1 = 1
- objectVariable1 = 2
- connection fails and should retry with objectVariable1 = 1
Quick and dirty solution:
-(void) post: (NSString *) post withParams: (NSDictionary *) params andReplies: (NSInteger) replies
{
[MANAGER POST:post parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject)
{
//PROCESS RESPONSE
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
//PROCESS FAILURE
if (replies > 0) {
[self post: post withParams: params andReplies: replies - 1];
}
}];
}
I'm posting a notification in the request failure block:
[manager POST:path
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
if (operation.response.statusCode == 200) {
//message delegate
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[[NSNotificationCenter defaultCenter] postNotificationName:HOST_UNREACHABLE object:operation];
}];
In the method that receives the notification, the completionBlock attribute is nil.
How do I access it without subclassing & overriding?
First to answer the question of how to send a block to an NSNotification:
The way you're attempting to do it is dangerous, because we don't know how AFHTTPSessionManager handles the blocks you pass it, and, unless its in the public interface, what it does may not remain fixed over time.
So, make a local variable to represent the block you want to pass, say, the completionBlock...
// this is a local variable declaration of the block
void (^completionBlock)(AFHTTPRequestOperation*,id) = ^(AFHTTPRequestOperation *operation, id response) {
if (operation.response.statusCode == 200) {
//message delegate
}
};
[manager POST:path
parameters:nil
success:completionBlock
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[[NSNotificationCenter defaultCenter] postNotificationName:HOST_UNREACHABLE object:completionBlock];
}];
The observer can get the block and invoke it this way...
- (void)didReceiveNotification:(NSNotification *)notification {
void (^completionBlock)(AFHTTPRequestOperation*,id) = notification.object;
// use it
[manager POST:someOtherPath
parameters:nil
success:completionBlock
// etc.
];
}
But I think the approach is strange. It spreads out responsibility for making the request to the object that gets notified, leaving it needing to know the path to retry the parameters (which you don't have in this case, but you might one day).
Consider instead subclassing the manager and adding behavior that does the retry. Now your manager subclass can be in charge of all requests, including retries, and your other classes are just customers who handle the outcome. Something like...
#interface MyAFHTTPRequestManager : AFHTTPSessionManager
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
retryURL:(NSString *)retryURLString
parameters:(nullable id)parameters
success:(nullable void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask *task, NSError *error))failure;
#end
Have your subclass implementation call super with the first URLString, and upon failure, call super with the retryURLString. e.g.
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
retryURL:(NSString *)retryURLString
parameters:(nullable id)parameters
success:(nullable void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask *task, NSError *error))failure {
[super POST:URLString parameters:parameters success:success
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[super POST:retryURLString parameters:parameters success:success failure:failure];
}];
}
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)
}];];
Hi I am making post request using AFnetworking 2.0.
My request looks like this.
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFXMLParserResponseSerializer serializer];
[manager.requestSerializer setValue:#"some value" forHTTPHeaderField:#"x"];
[manager POST:url parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
//doing something
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// error handling.
}];
How can i cancel this request???
POST method return the AFHTTPRequestOperation operation. You can cancel it by calling cancel.
AFHTTPRequestOperation *post =[manager POST:nil parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
//doing something
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// error handling.
}];
//Cancel operation
[post cancel];
Tried [manager.operationQueue cancelAllOperations] ?
I am using afnetworking and AFHTTPRequestOperationManager,
I have a singleton class, which contains all my api call. However, when I have concurrent api call, wrong data is being returned. API call A is returning API call B response?
CHAFHTTPRequestOperationManager is a subclass of AFHTTPRequestOperationManager
Anyone experience the same problem, what do I need to do to solve this:
NSString *path = [NSString stringWithFormat:#"users/%#/profile_photo", userName];
CHAFHTTPRequestOperationManager *manager = [CHAFHTTPRequestOperationManager sharedManagerObj];
[manager GET:path
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}
];
}