从ASIHTTPRequest转换到AFNetworking

4

由于不幸地停止了ASIHTTP项目的工作,以及后来发现AFNetworking代码库更好、更小,因此我正在将我的应用程序例程从ASIHTTP转换为AFNetworking。

但我遇到了几个问题。我的ASIHTTPRequest代码是作为一个方法构建的。这个方法需要一些参数,并将这些参数发布到一个URL上...然后返回结果数据。这些数据总是文本格式,但为了制作一个通用的方法,有时可能是json、有时是XML或者HTML。因此,我将这个方法构建为一个独立的通用URL下载器。

我的问题是,当调用这个例程时,我必须等待响应。我知道所有“同步是不好的”论点......我并不经常这么做......但对于某些方法,我想要同步。

所以,我的问题是:下面是我简化的ASIHTTP代码,以及我能想到的在AFNetworking中编写此代码的唯一方法。问题是,AFNetworking有时在返回方法之前就无法获得响应。@mattt给出的[operation waitUntilFinished]提示完全无法保持线程,直到完成块被调用......而我的另一种方法[queue waitUntilAllOperationsAreFinished]也不一定总是有效的(并且不会触发[operation hasAcceptableStatusCode]子句的错误部分)。因此,如果有人可以帮忙,在不使用“设计异步”这个常见建议的情况下,请提供帮助。

ASIHTTP版本:

- (NSString *) queryChatSystem:(NSMutableDictionary *) theDict
{
    NSString *response = [NSString stringWithString:@""];
    NSString *theUrlString = [NSString stringWithFormat:@"%@%@",kDataDomain,kPathToChatScript];

    ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:theUrlString]];
    for (id key in theDict)
    {
        [request setPostValue:[theDict objectForKey:key] forKey:key];
    }

    [request setNumberOfTimesToRetryOnTimeout:3];
    [request setAllowCompressedResponse:YES];
    [request startSynchronous];

    NSError *error = [request error];
    if (! error)
    {
        response = [request responseString];
    }

    return response;
}

AFNetworking版本

- (NSString *) af_queryChatSystem:(NSMutableDictionary *) theDict
{
    NSMutableDictionary *theParams = [NSMutableDictionary dictionaryWithCapacity:1];

    for (id key in theDict)
    {
        [theParams setObject:[theDict objectForKey:key] forKey:key];
    }


    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:kDataDomain]];

    NSMutableURLRequest *theRequest = [httpClient requestWithMethod:@"POST" path:[NSString stringWithFormat:@"/%@",kPathToChatScript] parameters:theParams];


    __block NSString *responseString = [NSString stringWithString:@""];

    AFHTTPRequestOperation *operation = [[[AFHTTPRequestOperation alloc] initWithRequest:theRequest] autorelease];

    operation.completionBlock = ^ {
        if ([operation hasAcceptableStatusCode]) {
            responseString = [operation responseString];
            NSLog(@"hasAcceptableStatusCode: %@",responseString);
        }
        else
        {
            NSLog(@"[Error]: (%@ %@) %@", [operation.request HTTPMethod], [[operation.request URL] relativePath], operation.error);
        }
    };

    NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];
    [queue addOperation:operation];
    [queue waitUntilAllOperationsAreFinished];
    [httpClient release];


    return responseString;

}

非常感谢您提供的任何想法。
3个回答

3
- (void)af_queryChatSystem:(NSMutableDictionary *) theDict block:(void (^)(NSString *string))block {
...
}

现在在completionBlock中执行以下操作:

block(operation.responseString);

该块将作为操作的代理。删除

-waitUntilAllOperationsAreFinished

并且

return responseString

您可以这样调用:

您可以这样调用:

[YourInstance af_queryChatSystem:Dict block:^(NSString *string) {
    // use string here
}];

希望能帮到你。你可以参考iOS示例中的AFNetworking。

是的,确实如此。非常感谢。我要学习更多关于块的知识,以便开始更好地使用它们。 - Jann

0

我强烈建议利用这个机会转换到苹果自己的NSURLConnection,而不是采用另一个第三方API。这样你就可以确定它不会被停用。我发现所需的额外工作是极少的 - 但它证明更加强大且更少出错。


谢谢,但正如我所说,此时此刻我更愿意使用AFNetworking。 - Jann
我认为你的论点有些不诚实,因为你轻视第三方库。AFNetworking已经在其核心中采用了一个薄的“NSOperation”包装器来包装你所提倡的“NSURLConnection”。为什么要重复造轮子,并忽略社区已经积极投入到这个库中的数百个小时的工作呢? - mattt
1
我理解你的观点。我的建议基于个人经验,绝不是轻视。使用苹果示例提供的代码,我从未需要更多的代码行数。许多库提供了简化,但开发人员仍然必须阅读API文档,只是他们自己的文档而不是苹果的,这是一个值得怀疑的权衡。现在,“数百小时的工作”不再受支持,我的建议是真诚的并且是出于好意。请考虑撤销您的反对票。 - Mundi

0

我的解决方案是手动运行当前线程的runloop,直到回调被处理。

这是我的代码。

- (void)testRequest
{
    MyHTTPClient* api = [MyHTTPClient sharedInstance]; // subclass of AFHTTPClient
    NSDictionary* parameters = [NSDictionary dictionary]; // add query parameters to this dict.
    __block int status = 0;
    AFJSONRequestOperation* request = [api getPath:@"path/to/test"
                                        parameters:parameters
                                           success:^(AFHTTPRequestOperation *operation, id responseObject) {
                                               // success code
                                               status = 1;
                                               NSLog(@"succeeded");
                                           } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                                               // failure
                                               status = 2;
                                               NSLog(@"failed");
                                           }];
    [api enqueueHTTPRequestOperation:request];
    [api.operationQueue waitUntilAllOperationsAreFinished];

    while (status == 0)
    {

        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                                 beforeDate:[NSDate date]];
    }

    STAssertEquals(status, 1, @"success block was executed");
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接