Search code examples
iosobjective-cafnetworkingafnetworking-2

AFnetworking synchronise in objective C


I've created a class Server Manager to handle all server communication stuff which includes AFnetworking files.

The instance is alloced in this way, and it is able to operate GET or POST request.

+ (ServerManager*) instance
{
    static ServerManager *Instance = nil;
    static dispatch_once_t onceToken = 0;
    dispatch_once(&onceToken, ^{
        Instance = [[ServerManager alloc]init];
    });
    return Instance;
}

But my question is, when I want to get the response from the server outside the class? How can I implement that in the synchronized way?

For example,in the view controller I've:

 ServerManager *serverManager = [ServerManager instance];

then I called class method in ServerManager for post request which returns a int.

int i = [serverManager postOperation:params];

The variable "i" is not assigned and next statement is called. Then server gives back the response after few seconds. How can I get a synchronised way here for assign the server response to local? In the class method, I've called:

 [AFHTTPRequestOperationManager POST:url parameters:params 
    success^(AFHTTPRequestOperation *operation, id responseObject){
    ....;
    }failure^(AFHTTPRequestOperation *operation, NSError *error){
    ....;
   }

Solution

  • So what's happening here is AFNetworking is sending out the server POST request on another thread, and then moving onto execute the line after int i = [serverManager postOperation:params]; You actually don't want to block/stop all behavior (ie: make it synchronous) until the server returns its response and assigns it to int i, because that would result in an unresponsive app, and frustrating experience for the user, so the fact that execution moves onto the next line is desirable. You want to allow AFNetworking to send out its request on another thread, while your app still remains responsive to user interactions.

    A clean way to do this is to send a completion block into that method to be called in the success block of AFNetworking. Wrap your call to [AFHTTPRequestOperationManager POST:url parameters:params.... inside a method, and call that.

    For example:

    - (void)registerUserWithCompletion:(void (^)(NSArray *results))completion
    {
      [AFHTTPRequestOperationManager POST:url parameters:params success^(AFHTTPRequestOperation *operation, id responseObject){
        NSArray *results = [responseObject valueForKey:@"results"];
        if(completion){
          completion(results);
        }
        } failure^(AFHTTPRequestOperation *operation, NSError *error){
          if(completion){
            NSLog(@"Error: %@", error);
            completion(nil); // send nil to indicate the call has failed for some reason.
          }
       }];
     }
    

    Then call that method like so:

    [self registerUserWithCompletion:^(NSArray *results) {
       if (results.count > 0) {
       // API call was successful. Do something with the results.
       NSNumber *i = [results objectAtIndex:0];
       // Do something with that variable.
       }
    }];