ios - GCD 等待 NSURLSessionDataTask 完成

标签 ios objective-c grand-central-dispatch

我有一个 UITableViewController,称它为 TableViewControllerA,它是我创建的另一个对象 APICallerB 的委托(delegate),用于与 API 通信。通过 NSURLSessionDataTask,APICallerB 正在设置其属性之一,然后将其设置为等于 TableViewControllerA 的属性之一。

这是 tableViewControllerA 的 viewDidLoad 方法:

- (void)viewDidLoad {

    [super viewDidLoad];

    // init instance of APICallerB
    APICallerB *acb = [[APICallerB alloc] init];

    // Set TableViewControllerA as delegate
    tvcA.delegate = self;


    [acb makeAPICallWithArgument:self.argument];


    self.property1 = acb.property2;
}

我的问题是:WAITING [acb makeAPICallWithARgument:self.argument] 完成的最佳方式是什么,以便 self.property1 = acb.property2 将工作?我假设可以使用 GCD(`dispatch_sync'?)但是,作为 iOS/Objective-C 的新手,我不确定在哪里使用它。还是将其中一项或两项移到别处会更好?

这是来自 APICallerB 的方法:

- (void)makeAPICallWithArgument:(NSString *)arg
{


    NSString *requestString = [NSString stringWithFormat:@"http://%@:%@@apiurl.com/json/Request?arg=%@", API_USERNAME, API_KEY, arg];
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration ephemeralSessionConfiguration];
    config.HTTPAdditionalHeaders = @{@"Accept" : @"application/json"};
    NSURLSession *urlSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];

    NSURL *url = [NSURL URLWithString:requestString];
    NSURLRequest *req = [NSURLRequest requestWithURL:url];

    NSURLSessionDataTask *dataTask = [urlSession dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {

        NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
        NSArray *ar = [jsonObject[@"Result"] objectForKey:@"results"];
        self.property2 = ar;
        }];

  [dataTask resume];
}

最佳答案

您正在调用异步方法,因此您应该使用异步模式。例如,完成 block 实现可能如下所示:

- (void)makeAPICallWithArgument:(NSString *)arg completionHandler:(void (^)(NSArray *results, NSError *error))completionHandler
{
    NSString *requestString = [NSString stringWithFormat:@"http://%@:%@@apiurl.com/json/Request?arg=%@", API_USERNAME, API_KEY, arg];
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration ephemeralSessionConfiguration];
    config.HTTPAdditionalHeaders = @{@"Accept" : @"application/json"};
    NSURLSession *urlSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];

    NSURL *url = [NSURL URLWithString:requestString];
    NSURLRequest *req = [NSURLRequest requestWithURL:url];

    NSURLSessionDataTask *dataTask = [urlSession dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (completionHandler) {
            if (error) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    completionHandler(nil, error);
                });
            } else {
                NSError *parseError;
                NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
                dispatch_async(dispatch_get_main_queue(), ^{
                    completionHandler(jsonObject[@"Result"][@"results"], parseError);
                });
            }
        }
    }];

    [dataTask resume];
}

你会这样调用它:

[acb makeAPICallWithArgument:self.argument completionHandler:^(NSArray *results, NSError *error){
    // you'd probably first check to make sure you didn't have an error

    self.property1 = results;
}];

几个小观察:

  1. 我可能不会每次都创建一个新 session 。如果您希望调用多个电话,请保存此 session 以备将来请求。

  2. 您的 makeAPICallWithArgument 正在更新一个属性,您稍后会尝试检索该属性。我会停用该属性,并将值作为参数传回完成 block 。

  3. 我在其中添加了一些错误处理。

  4. 您的 [jsonObject[@"Result"] objectForKey:@"results"] 看起来不太对。你真的有 JSON 返回一个键为“Result”的字典,并在另一个字典中返回一个键为“results”的字典。如果是这样,很好,但这看起来很可疑。即使那是您的 JSON 格式,我也会将其简化为 jsonObject[@"Result"][@"results"]

  5. 有人建议您考虑使用信号量。这几乎总是一个坏主意。这用于使异步方法同步运行。但是你永远不想阻塞主队列。

    使用完成 block 模式消除了对信号量的需要。 Apple 提供异步 API 是有原因的,所以我们在使用时应该采用异步模式。

关于ios - GCD 等待 NSURLSessionDataTask 完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26439677/

相关文章:

ios - 跟踪用户当前位置后的 Google map myLocation 按钮颜色 - ios

ios - App在后台时,APNS token是否发生变化或失效?

ios - ld : library not found for -lJTCalendar on iOS Simulator

objective-c - 发送到 Objective-C 中的对象的消息是否可以被监视或打印出来?

objective-c - 如果我正在进行手动内存管理,应使用哪个 Json 库

ios - appname.ViewsVC collectionView :cellForItemAtIndexPath:]: unrecognized selector sent to instance

ios - XCUITest:找不到匹配元素

ios - 异步操作未按顺序完成

ios - 没有 DispatchQueue.main.async 的意外布局行为

ios - semaphore_wait_trap、GCD 和 CocoaAsyncSocket