【问题标题】:Xcode, ensure codes after blocks run later for NSURLConnection asynchronous requestXcode,确保块之后的代码稍后运行以用于 NSURLConnection 异步请求
【发布时间】:2012-07-21 08:15:03
【问题描述】:

您好:我一直在编写一个 iOS 程序,它使用许多对后端 Rails 服务器的 http 查询,因此有大量如下所示的代码。在这种情况下,它正在更新 UITableView:

//making requests before this...
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse* response, NSData* data, NSError* error)
{
    NSLog(@"Request sent!");

    NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
    NSLog(@"Response code: %d", [httpResponse statusCode]);
    if ([data length] > 0 && error == nil){
        NSLog(@"%lu bytes of data was returned.", (unsigned long)[data length]); }
    else if ([data length] == 0 &&
             error == nil){
        NSLog(@"No data was returned.");
    }
    else if (error != nil){
        NSLog(@"Error happened = %@", error); }

    id jsonObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
    if (jsonObject != nil && error == nil){
        NSLog(@"Successfully deserialized...");
        if ([jsonObject isKindOfClass:[NSDictionary class]]){
            NSDictionary *deserializedDictionary = (NSDictionary *)jsonObject;
            NSLog(@"Dersialized JSON Dictionary = %@", deserializedDictionary);
            [listOfItems addObject:deserializedDictionary];
        }
        else if ([jsonObject isKindOfClass:[NSArray class]]){
            NSArray *deserializedArray = (NSArray *)jsonObject; 
            NSLog(@"Dersialized JSON Array = %@", deserializedArray);
            [listOfItems addObjectsFromArray:deserializedArray];
        }
        else {
            /* Some other object was returned. We don't know how to deal
             with this situation as the deserializer only returns dictionaries
             or arrays */ }
    }
    else if (error != nil){
        NSLog(@"An error happened while deserializing the JSON data., Domain: %@, Code: %d", [error domain], [error code]); 
    }
    [self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];
}];
//the place where never runs
NSLog(@"End of function.");

问题是:最后一行通常在代码块之前执行。如何确保块后的代码实际在块后运行?

我知道该块使用了一些其他线程,这就是我使用performSelectorOnMainThread 函数而不是直接调用[self.tableView reloadData] 的原因。但是如果我以后想做别的事情,我该怎么做呢?

另外,谁能展示一些更好的方法来做到这一点?我正在尝试找出对后端进行大量调用的最佳方法。有几种方法可以发出异步请求,包括这种阻塞方式和另一种调用委托类的老式方式。在重构代码的过程中,我还尝试创建自己的委托类并让其他类调用它,但是很难确定回调函数针对它返回的连接数据的正确行为,尤其是对于使用多个函数的类调用不同的请求。而且我不想使用同步调用。

非常感谢您的任何回答。也欢迎指出代码中的任何错误。

【问题讨论】:

  • 您是否在到达异步块末尾之前看到“函数结束”打印?即在“请求已发送!”之前
  • 非常抱歉,我在发布此问题后立即看到了这一点。所以我编辑了它,并在这里继续问其他问题。感谢您的通知。
  • 今年 WWDC 的 Session 211 有很多关于使用 NSOperationQueue 实现这种结构的信息,这是一个很棒的演讲。

标签: iphone xcode asynchronous objective-c-blocks nsurlrequest


【解决方案1】:

您可以使用调度组

示例代码:

- (void)doSomethingAndWait {
// synchronous method
// called in main thread is not good idea.
NSAssert(! [NSThread isMainThread], @"this method can't run in main thread.");

dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);

//making requests before this...
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse* response, NSData* data, NSError* error)
{
    // your work here.


    dispatch_group_leave(group);
}];

// wait for block finished
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(group);

//will call until block is finished.
NSLog(@"End of function.");
}

要调用该方法,您需要避免在主线程中调用它。

你应该这样称呼它

dispatch_queue_t queue = dispatch_queue_create("com.COMPANYNAME.APPNAME.TASKNAME", NULL);
    dispatch_async(queue, ^{
        [self doSomethingAndWait];
    });

【讨论】:

  • 谢谢。看起来还蛮有用的。我尝试了另一种方式,在异步块中使用同步请求以使重构更容易。 Cookbook(猫书)也给出了这样的例子。对于第一种方式,由于该处理程序,将其包装在我自己的类中调用有点困难,因为我希望普遍返回响应数据。这些是唯一的方法吗?
猜你喜欢
  • 2021-12-10
  • 2014-12-16
  • 2012-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多