什么被认为是重载主线程?

时间:2013-03-19 15:47:57

标签: macos cocoa user-interface timer grand-central-dispatch

我在用户界面上显示来自数据模型的信息。我目前的做法是通过授权如下:

@protocol DataModelDelegate <NSObject>
- (void)updateUIFromDataModel;
@end

我在我的控制器类中实现了委托方法,如下所示,使用GCD将UI更新推送到主线程:

- (void)updateUIFromDataModel {

    dispatch_async(dispatch_get_main_queue(), ^{

        // Code to update various UI controllers
        // ...
        // ...

    });
}

我关心的是,在某些情况下,这种方法可以非常频繁地调用(每秒约1000次,每次更新多个UI对象),这对我来说非常像我在'垃圾邮件'主线程用命令。

发送到主线程是否太多了?如果有的话,是否有人对什么是接近这个的最佳方式有任何想法?

我已经查看了dispatch_apply,但是在合并数据时这看起来更有用,这不是我所追求的 - 我真的只是想跳过更新,如果它们太频繁,那么只有理智的数量更新发送到主线程!

我正在考虑采用不同的方法并实施计时器而不是每10毫秒轮询数据,但是由于数据更新往往是零星的,我觉得这样做会很浪费。

结合这两种方法,我考虑的另一个选项是等待更新消息并通过设置定时器以设定的间隔轮询数据来响应,然后在数据似乎已停止更改时禁用定时器。但这会使问题过于复杂吗,理智的方法是简单地运行一个恒定的计时器吗?

编辑 在下面添加了一个答案,显示了使用调度源的调整

3 个答案:

答案 0 :(得分:7)

一种选择是使用Dispatch Source类型DISPATCH_SOURCE_TYPE_DATA_OR,它允许您重复发布事件并让libdispatch将它们组合在一起。如果您要发布内容,可以使用dispatch_source_merge_data让它知道有新功能。如果目标队列(在您的情况下,主队列)忙,则会将dispatch_source_merge_data的多个调用合并在一起。

答案 1 :(得分:5)

我一直在尝试使用调度源并让它按预期工作 - 这是我如何调整我的类实现,以防任何人遇到这个问题:

@implementation AppController {
@private
    dispatch_source_t _gcdUpdateUI;
}

- (void)awakeFromNib {

    // Added the following code to set up the dispatch source event handler:

    _gcdUpdateUI = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, 
                                          dispatch_get_main_queue());
    dispatch_source_set_event_handler(_gcdUpdateUI, ^{

        // For each UI element I want to update, pull data from model object:
        // For testing purposes - print out a notification:
        printf("Data Received. Messages Passed: %ld\n", 
               dispatch_source_get_data(_gcdUpdateUI));
    });

dispatch_resume(_gcdUpdateUI);

}

现在在委托方法中我删除了对dispatch_async的调用,并将其替换为以下内容:

- (void)updateUIFromDataModel {

  dispatch_source_merge_data(_gcdUpdateUI, 1);

}

这对我来说非常好。现在即使在最激烈的数据更新期间,UI也能保持完美响应。

尽管printf()输出是检查合并是否正常工作的一种非常粗略的方式,但是快速滚动控制台输出显示我打印出的大部分消息的值为1(很容易98%)然而,当模型发送最多更新消息时,间歇性跳转到10-20左右,达到了超过100个合并消息的峰值。

再次感谢您的帮助!

答案 2 :(得分:2)

如果应用程序在重载下沙滩球,那么您已经阻止主线程太长时间,并且您需要为UI更新实施合并策略。如果应用程序仍然对点击有响应,并且没有沙滩球,那么你没事。

相关问题