0

I'm working on an app at the moment which allows users to authenticate to a remote server using an HTTP request (in JSON format).

I've created a separate class to handle the API Request as it's something I'll be doing a lot of throughout the application.

The method in APIRequest where most of the magic takes place is:

-(void)send
{
    self.isLoading = YES;
    request_obj = [[self httpClient] requestWithMethod:method path:extendedResourcePath parameters:params];
    AFJSONRequestOperation *operation = [AFJSONRequestOperation 
                                         JSONRequestOperationWithRequest:request_obj 
                                        success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
                                            self.response = [[APIResponse alloc] initWithResponse:response andJSON:JSON];
                                            self.isLoading = NO;
                                        } 
                                        failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
                                            self.isLoading = NO;
                                        }];

    // queue is defined elsewhere in the class as an instance of NSOperationQueue
    [queue addOperation:operation];
}

In my controller, when a button is pressed I call:

// set the session params from the form values
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys: 
                        self.usernameField.text, @"session[username]", 
                        self.passwordField.text, @"session[password]", nil];

// create a new API request object
api_request = [[APIRequest alloc] initWithReourcePath:@"sessions" andMethod:HTTPMethodPOST andParams:params];

// send the request
[api_request send];

What I can't seem to work out is how to notify the controller that the request is complete.

I have a property on APIRequest called isLoading which will be "YES" as long as the request is still taking place. So, I know I can check if the api_request is done by asking it.

I can't think of any events that the controller would respond to a few seconds later in order to ask the api_request if it's complete though.

Can anyone advise a good approach here?

bodacious
  • 6,608
  • 9
  • 45
  • 74

4 Answers4

0

I asked this same question two days ago... wish I had seen this first. There are 2 ways I am going to try to implement this. One, create a delegate in my Services class that will trigger methods in my ViewController (See this answer)...

or Two, create a method containing callback blocks... Similar to this questions answer.

Community
  • 1
  • 1
andreortiz
  • 43
  • 1
  • 4
0

Two quick solutions:

  1. Use NSNotificationCenter (it's available on iOS) to post a message in the completion handling block. Your controller can subscribe for an appropriate message and be notified about the operation status.
  2. Subclass AFJSONRequestOperation and add a "delegate" property. Add something like [[self delegate] performSelectorOnMainThread:@selector(operationSucceded:) withObject:self waitUntilDone:NO]; into the handling blocks.

I personally prefer the first way since I try to avoid subclassing in such simple situations.

Gobra
  • 4,263
  • 2
  • 15
  • 20
0

I think another way is to use KVO.

// Add observer for your key
[api_request addObserver:self forKeyPath:@"isLoading" options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOption) context:NULL];

// Add below method into your implementation
- (void)observeValueForKeyPath:(NSString *)keyPath  
                      ofObject:(id)object  
                        change:(NSDictionary *)change  
                       context:(void *)context
{
    // put your stuffs here...
}
0

Don't use those global booleans to track connection state, instead change the -send: method signature into a method that takes blocks and calls the blocks upon completion. I do this quite often. An example from a project I work on:

- (void)getDealsWithSuccess:(void (^)(NSArray *deals))success failure:(void (^)(NSError *error))failure
{
    // lots of OAuth + Request creation code here ...

    AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request 
     success:^ (NSURLRequest *request, NSURLResponse *response, id json) {
        NSLog(@"%@", json);

        // handle result here, e.g. 
        // I convert the json to a array with custom objects here ...

        if (success) 
            success(deals);

    } failure:^ (NSURLRequest *request, NSURLResponse *response, NSError *error, id json) {
        NSLog(@"%@", error);

        // handle error here ..

        if (failure)
            failure(error);
    }];

    [operation start];
}
Wolfgang Schreurs
  • 11,779
  • 7
  • 51
  • 92