2012-05-20 57 views
7

我正在用AFNetworking发出JSON请求,然后调用[operation waitUntilFinished]以等待操作和成功或失败块。但是,它似乎,虽然右下降 - 在日志消息方面,我得到 “0”, “3”, “1”,而不是 “0”, “1”, “3”等待完成块在AFNetworking请求中完成

NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://google.com"]]; 
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url]; 
httpClient.parameterEncoding = AFFormURLParameterEncoding; 
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:@"query", @"q", nil]; 
NSMutableURLRequest *request = [httpClient requestWithMethod:@"GET" path:[url path] parameters:params]; 
NSLog(@"0"); 
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *innerRequest, NSHTTPURLResponse *response, id JSON) { 
NSLog(@"1"); 
gotResponse = YES; 
} failure:^(NSURLRequest *innerRequest, NSHTTPURLResponse *response, NSError *error, id JSON) { 
    NSLog(@"2"); 
    gotResponse = YES; 
}]; 
NSLog(@"Starting request"); 
[operation start]; 
[operation waitUntilFinished]; 
NSLog(@"3"); 
+0

似乎对'[operation waitUntilFinished]'的调用不会等待完成块。 AFJSONRequestOperation.m使用'dispatch_async'执行它们,我认为它成为单独操作的一部分。这是否正确,是否有解决方法? – Kamran

回答

14

这是通过使用AFNetworking设置请求,但是进行同步呼叫,然后手动处理完成块。很简单。 AFNetworking似乎不支持这个https://github.com/AFNetworking/AFNetworking/wiki/AFNetworking-FAQ,尽管解决方法很简单。

#import "SimpleClient.h" 

#import "AFHTTPClient.h" 
#import "AFJSONRequestOperation.h" 
#import "AFJSONUtilities.h" 

@implementation SimpleClient 

+ (void) makeRequestTo:(NSString *) urlStr 
     parameters:(NSDictionary *) params 
     successCallback:(void (^)(id jsonResponse)) successCallback 
     errorCallback:(void (^)(NSError * error, NSString *errorMsg)) errorCallback { 

    NSURLResponse *response = nil; 
    NSError *error = nil; 

    NSURL *url = [NSURL URLWithString:urlStr]; 

    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url]; 

    httpClient.parameterEncoding = AFFormURLParameterEncoding; 

    NSMutableURLRequest *request = [httpClient requestWithMethod:@"POST" path:[url path] parameters:params]; 
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; 

    if(error) { 
     errorCallback(error, nil); 
    } else { 
     id JSON = AFJSONDecode(data, &error); 
     successCallback(JSON); 
    } 
} 

@end 
0

那应该(几乎)工作。您对

NSMutableURLRequest *request = [httpClient requestWithMethod:@"GET" path:[url path] parameters:params]; 

通话可能不应该通过[url path]path:参数。在AFNetworking土地上,该路径是基础URL之后的所有内容(例如,基本URL可以是“http://google.com”,路径“/ gmail”或其他)。

话虽这么说,它可能不是一个好主意,使异步操作与waitUntilFinished线程阻塞同步操作,但我敢肯定,你有你的理由...;)

+0

更改为路径:@“/”,但结果相同。 – Kamran

0

我刚刚有同样的问题,并找到了不同的解决方案。我有两个相互依赖的操作,但可以并行加载。但是,在完成第一个块的完成块之前,不能执行第二个操作的完成块。如Colin指出的那样,制作Web请求块可能是一个不好的选择。这对我来说很重要,所以我非同步地做到了。

这是我的解决方案:

// This is our lock 
@interface SomeController() { 
    NSLock *_dataLock; 
} 
@end 

@implementation 

// This is just an example, you might as well trigger both operations in separate 
// places if you get the locking right 
// This might be called e.g. in awakeFromNib 
- (void)someStartpoint { 
    AFJSONRequestOperation *operation1 = [AFJSONRequestOperation JSONRequestOperationWithRequest:[NSURLRequest requestWithURL:url1] 
                         success:^(NSURLRequest *request, NSHTTPURLResponse *response, id data) { 
     // We're done, we unlock so the next operation can continue its 
     // completion block 
     [_dataLock unlock]; 
    } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id data) { 
     // The request has failed, so we need to unlock for the next try 
     [_dataLock unlock]; 
    }]; 

    AFJSONRequestOperation *operation2 = [AFJSONRequestOperation JSONRequestOperationWithRequest:[NSURLRequest requestWithURL:url2] 
                         success:^(NSURLRequest *request, NSHTTPURLResponse *response, id data) { 
     // The completion block (or at least the blocking part must be run in a 
     // separate thread 
     [NSThread detachNewThreadSelector:@selector(completionBlockOfOperation2:) toTarget:self withObject:data]; 
    } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id data) { 
     // This second operation may fail without affecting the lock 
    }]; 

    // We need to lock before both operations are started 
    [_dataLock lock]; 

    // Order does not really matter here 
    [operation2 start]; 
    [operation1 start]; 
} 

- (void)completionBlockOfOperation2:(id)data { 
    // We wait for the first operation to finish its completion block 
    [_dataLock lock]; 

    // It's done, so we can continue 

    // We need to unlock afterwards, so a next call to one of the operations 
    // wouldn't deadlock 
    [_dataLock unlock]; 
} 

@end 
+0

为什么使用异步请求,然后强制它阻止?这很容易出错,因为如果您在获取解锁语句之前可能会从回调中返回。 – Kamran

+0

这不是阻止的请求。这是一旦请求完成后调用的lambda函数。这可以确保第二个(依赖)请求的响应在第一个请求完成之前不会被评估。请求本身是并行完成的。 – Koraktor

0

使用委托方法调用

里面放块的方法下载时会调用本身/上传完成。