7

AFNetworking で JSON リクエストを作成し、[operation waitUntilFinished] を呼び出して、操作と成功または失敗のブロックを待機しています。しかし、それは正しいようです-ログメッセージに関しては、「0」、「1」、「3」の代わりに「0」、「3」、「1」が表示されます

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");
4

4 に答える 4

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
于 2012-05-20T18:37:51.033 に答える
0

Delegate メソッド呼び出しを使用する

ダウンロード/アップロードが完了したときに自分自身を呼び出すメソッドをブロック内に配置します。

于 2015-01-15T12:56:11.787 に答える
0

私はちょうど同じ問題を抱えていて、別の解決策を見つけました。互いに依存する 2 つの操作がありましたが、同時に読み込むことができます。ただし、最初の操作の完了ブロックが完了する前に、2 番目の操作の完了ブロックを実行することはできません。

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
于 2012-05-24T05:52:06.240 に答える
0

それは(ほぼ)うまくいくはずです。への電話

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

おそらくパラメーター[url path]に渡すべきではありません。path:AFNetworking の世界では、そのパスはベース URL の後のすべてです (たとえば、ベース URL は "http://google.com" とパス "/gmail" などです)。

そうは言っても、非同期操作をwaitUntilFinishedでスレッドブロック同期操作にするのはおそらく良い考えではありませんが、あなたには理由があると確信しています... ;)

于 2012-05-20T05:18:08.247 に答える