4

I have a class, "WebAPI", that handles all web API calls, the class uses NSURLConnection through its asynchronous delegate-based calls.

Whenever an object needs to communicate with the web API it will use an instance of WebAPI and call the required method as shown below in the case of signing in I make the folowing call from the AppDelegate:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
     WebAPI *webAPI = [[WebAPI alloc] init];
     [webAPI performLoginWithUserName:@"test1@myserver.com" andPassword:@"password"];
}

The problem is that once the performLoginWithUserName:andPassword call is made, the code progresses on and any/all response is received in the delegate methods that are implemented in WebAPI.m.

This is a real issue because I need to be able to get response codes and any data received within the class method from where the call to the WebAPI, originated . I would like to be able to this :

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
     WebAPI *webAPI = [[WebAPI alloc] init];
     WebAPIResponse * webAPIRespnse = [webAPI performLoginWithUserName:@"test1@myserver.com" andPassword:@"password"];
}

Where WebAPIResponse class is a custom class that will contain the HTTP Status code and any data that is received.

This is achievable if I change WebAPI.m to use NSURLConnection sendSynchronousRequest, but that doesnt enable me to receive all HTTP codes.

What would be the best way to fulfill this requirement?

Thank you for your help.

Shumais Ul Haq
  • 1,427
  • 1
  • 15
  • 26
  • Due to the asynchronous nature of the delegate implementation this is a pretty weird thing to do. After all, in the code above you want the `WebAPIResponse` to be ready immediatly while your `WebAPI` is still handling the request. IMO a more sensible solution would be to add support for a delegate object in your `WebAPI` class... – Hless Apr 14 '14 at 09:46
  • Not immediately, I do understand that doing what I need would require the NSURLConnection to complete and receive response and data, it is more like as soon as the information is available for return. – Shumais Ul Haq Apr 14 '14 at 09:58

2 Answers2

2

You could use blocks to handle responses. For example:

WebApi.h
- (void)performLoginWithUsername:(NSString *)userName 
                     andPassword:(NSString *)password
                    successBlock:(void(^)(NSData *response))successBlock
                    failureBlock:(void(^)(NSError *error))failureBlock;

WebApi.m
@interface WebAPI()
    @property (nonatomic, copy) void(^authorizationSuccessBlock)(NSData *response);
    @property (nonatomic, copy) void(^authorizationFailureBlock)(NSError *error);
@end

@implementation WebAPI
- (void)performLoginWithUsername:(NSString *)userName 
                     andPassword:(NSString *)password
                    successBlock:(void(^)(NSData *response))successBlock
                    failureBlock:(void(^)(NSError *error))failureBlock {
    self.authorizationSuccessBlock = successBlock;
    self.authorizationFailureBlock = failureBlock;
    // NSURLConnection call for authorization here
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    if (self.authorizationSuccessBlock != nil) {
        self.authorizationSuccessBlock(data);
        self.authorizationSuccessBlock = nil;
    }
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    if (self.authorizationFailureBlock != nil) {
        self.authorizationFailureBlock(error);
        self.authorizationFailureBlock = nil;
    }
}

AppDelegate.m
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
   WebAPI *webAPI = [[WebAPI alloc] init];
   [webAPI performLoginWithUserName:@"test1@myserver.com" andPassword:@"password" successBlock:^(NSData *response) {
      // Handle result here
   } failureBlock:^(NSError *error) {
      // Handle error here
   }];

}

Vlad Papko
  • 13,184
  • 4
  • 41
  • 57
0

Change your WebAPI class to provide a delegate interface of its own, or to use completion blocks on the request which are called when the asynchronous connection completes.

Wain
  • 118,658
  • 15
  • 128
  • 151
  • I have thought about implementing delegates but that only enables me to receive response within the calling class rather than the calling method. The response/data need to consumed within the method from where the webAPI call was made from. – Shumais Ul Haq Apr 14 '14 at 10:03
  • Then you need to change that method. Move the functionality to another method. Show an activity indicator + cancel button to the user while they wait. You shouldn't use the synchronous call. – Wain Apr 14 '14 at 10:06
  • 1
    In that case definitely blocks, blocks contain a reference to the scope of the method where they are defined. – Hless Apr 14 '14 at 10:13