2012-05-20 25 views
7

Tôi đang thực hiện yêu cầu JSON với AFNetworking và sau đó gọi [operation waitUntilFinished] để chờ thao tác và các khối thành công hoặc lỗi. Tuy nhiên, dường như có vẻ đúng - theo thông báo nhật ký, tôi nhận được "0", "3", "1" thay vì "0", "1", "3"Chờ khối hoàn thành hoàn thành trong yêu cầu 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

Dường như cuộc gọi đến '[operation waitUntilFinished]' không chờ các khối hoàn thành. AFJSONRequestOperation.m thực hiện chúng với 'dispatch_async' mà tôi nghĩ là một phần của một hoạt động riêng biệt. Điều này có đúng không và có cách nào không? – Kamran

Trả lời

14

này hoạt động bằng cách bằng cách sử dụng AFNetworking để thiết lập các yêu cầu, nhưng thực hiện cuộc gọi đồng bộ, sau đó xử lý các khối hoàn thành theo cách thủ công. Rất đơn giản. AFNetworking dường như không hỗ trợ điều này https://github.com/AFNetworking/AFNetworking/wiki/AFNetworking-FAQ, mặc dù công việc xung quanh là đủ đơn giản.

#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

Điều đó nên (gần như) làm việc. Cuộc gọi của bạn đến

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

có lẽ không được vượt qua [url path] tham số path:. Trong vùng AFNetworking, đường dẫn đó là mọi thứ sau url cơ sở (ví dụ url cơ sở có thể là "http://google.com" và đường dẫn "/ gmail" hoặc bất kỳ thứ gì).

đó đang được nói, có lẽ không phải là một ý tưởng tốt để làm cho các hoạt động không đồng bộ vào một hoạt động đồng bộ thread-blocking với waitUntilFinished, nhưng tôi chắc chắn rằng bạn có lý do của bạn ...;)

+0

Đã thay đổi thành đường dẫn: @ "/", nhưng kết quả là như nhau. – Kamran

0

Tôi vừa gặp vấn đề tương tự và tìm ra giải pháp khác. Tôi có hai hoạt động phụ thuộc vào nhau, nhưng có thể tải song song. Tuy nhiên, khối hoàn thành của hoạt động thứ hai không thể được thực hiện trước khi khối hoàn thành của khối đầu tiên đã hoàn thành.

Như Colin đã chỉ ra, đó có thể là lựa chọn không tốt để tạo khối yêu cầu web. Điều này là rất cần thiết cho tôi, vì vậy tôi đã làm nó không đồng bộ.

Đây là giải pháp của tôi:

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

Tại sao sử dụng yêu cầu không đồng bộ, sau đó buộc nó chặn? Đây là lỗi dễ xảy ra vì nếu bạn có thể quay trở lại từ cuộc gọi lại trước khi nhận được câu lệnh mở khóa. – Kamran

+0

Đó không phải là yêu cầu đang chặn. Đó là hàm lambda được gọi khi yêu cầu kết thúc. Điều này đảm bảo đáp ứng của yêu cầu thứ hai (phụ thuộc) không được đánh giá cho đến khi yêu cầu đầu tiên được hoàn thành. Các yêu cầu được thực hiện song song. – Koraktor

0

Sử dụng phương pháp gọi Đại biểu

Đặt phương pháp bên trong khối mà sẽ gọi riêng của mình khi tải/tải lên hoàn tất.