如何处理iOS ViewControllers中的异步进程?

时间:2012-02-14 12:20:36

标签: objective-c ios5 xcode4.2 afnetworking

我正在开发一个应用程序,允许用户使用HTTP请求(JSON格式)对远程服务器进行身份验证。

我已经创建了一个单独的类来处理API请求,因为它将在整个应用程序中做很多事情。

APIRequest中大多数魔法发生的方法是:

-(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];
}

在我的控制器中,当按下按钮时,我打电话:

// 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];

我似乎无法解决的是如何通知控制器请求已完成。

我在APIRequest上有一个名为isLoading的属性,只要请求仍在进行,该属性将为“YES”。所以,我知道我可以通过询问来检查api_request是否完成。

我想不出控制器会在几秒钟之后响应的任何事件,以便询问api_request它是否完整。

有人可以在这里建议一个好的方法吗?

4 个答案:

答案 0 :(得分:0)

两个快速解决方案:

  1. 使用NSNotificationCenter(在iOS上可用)发布 完成处理块中的消息。你的控制器可以 订阅适当的消息并通知操作状态。
  2. 子类AFJSONRequestOperation并添加“委托”属性。将 [[self delegate] performSelectorOnMainThread:@selector(operationSucceded:) withObject:self waitUntilDone:NO];之类的内容添加到处理块中。
  3. 我个人更喜欢第一种方式,因为我试图在这种简单的情况下避免子类化。

答案 1 :(得分:0)

我认为另一种方法是使用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...
}

答案 2 :(得分:0)

不要使用那些全局布尔值来跟踪连接状态,而是将 -send:方法签名更改为一个方法,该方法接受块并在完成时调用块。我经常这样做。我工作的项目的一个例子:

- (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];
}

答案 3 :(得分:0)

我两天前问了同样的问题......希望我先看到这个问题。我将尝试两种方法来实现这一点。一,在我的Services类中创建一个委托,它将触发我的ViewController中的方法(See this answer)......

或者两个,创建一个包含回调块的方法......类似于这个问题的答案。