我的Grand Central Dispatch用法:我正确使用它吗?

时间:2013-07-30 15:46:48

标签: ios grand-central-dispatch

我以JSON格式从服务器获取数据。它只有大约150条记录,我最初没有使用GCD,但是当我点击应用程序中的按钮查看带有数据的表时,它会延迟大约几秒钟,然后切换到表格视图并显示数据。所以我实现了GCD,现在当我点击按钮时,它立即切换到tableview,但是加载数据有几秒延迟,这似乎比GCD之前的实现更长。所以我不确定我是否正确使用GCD,或者是否是我的服务器导致延迟(我认为是罪魁祸首)。这是一个名为retrieveData的方法中的GCD实现,我在viewDidLoad中调用[self retrieveData]:

- (void)retrieveData
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{

        NSURL *url = [NSURL URLWithString:@"http://MY_URL/JSON/document.json"];
        NSData * data = [NSData dataWithContentsOfURL:url];

        dispatch_async(dispatch_get_main_queue(), ^{

    json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];

    //Set up our exhibitors array
    exhibitorsArray = [[NSMutableArray alloc] init];

    for (int i = 0; i < json.count; i++) {
        //create exhibitors object
        NSString * blabel = [[json objectAtIndex:i] objectForKey:@"BoothLabel"];
        NSString * bName = [[json objectAtIndex:i] objectForKey:@"Name"];
        NSString * bURL = [[json objectAtIndex:i] objectForKey:@"HyperLnkFldVal"];


        exhibitors * myExhibitors = [[exhibitors alloc] initWithBoothName: bName   andboothLabel: blabel andBoothURL: bURL];

        //Add our exhibitors object to our exhibitorsArray
        [exhibitorsArray addObject:myExhibitors];

        //Sort by name
        NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
        [exhibitorsArray sortUsingDescriptors:[NSMutableArray arrayWithObject:sort]];

    }

    [self.myTableView reloadData];

        });
    });

}

1 个答案:

答案 0 :(得分:5)

这基本上是正确的。将数据检索分派到后台队列,然后将模型和UI更新分派回主队列。做得好。

就其变慢而言,我没有看到任何可以解释的事情。 GCD引入了一些开销,但通常无法观察到。这可能是一个“看着水壶永不沸腾”的问题。

但有几个无关的想法:

  1. 我可能会建议将排序移到for循环之外,但在reloadData之前。你要排序150次。如果进行插入排序,你可以在循环中完成,但我不认为这发生在这里。我将排序移动到循环结束。我不确定性能增益是否可以观察到,但应该有一些适度的改进。

  2. 您可能希望确保data不是nil(例如,没有网络或其他网络问题),因为如果是,JSONObjectWithData将崩溃。

  3. 您的json对象是外部变量。它应该是您的retrieveData方法的局部变量。没有必要使它成为实例变量。如果合适的话,将它变成局部变量会更清晰。

  4. 您可能应采用命名惯例,即类名以大写字母开头(例如Exhibitor而不是exhibitors)。

  5. 非常简短,但您的blabel变量应该是bLabel。更好的是,我可能会重命名这三个变量boothLabelboothNameboothUrlString

  6. 您正在为exhibitorsArray使用实例变量。我猜你也在其他地方这样做。您可能需要考虑使用declared properties

  7. 您可能希望在将代码分发到后台之前打开网络活动指示器,并在执行reloadData时将其关闭。

    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
    
  8. 如果你想变得非常复杂,你可能会重新考虑是否要使用GCD的全局队列(因为如果你快速刷新10次,那么所有10个都会运行,而你可能只希望运行最后一个) 。这是一个更复杂的主题,所以我不会在这里讨论,但如果您感兴趣,可能需要参考Concurrency Programming Guide操作队列的讨论,您可以在其中创建可取消的操作(因此,在启动新操作时,取消之前的操作)。

    您可能还想参考Building Concurrent User Interfaces on iOS WWDC 2012视频。

  9. 但这与你原来的问题完全不同:是的,你已经适当地解决了这个问题。