2012-05-20 99 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

使用委託方法調用

裏面放塊的方法下載時會調用本身/上傳完成。