1

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

@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 毫秒一次,但是由于数据更新往往是零星的,我觉得这样做会很浪费。

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

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

4

3 回答 3

7

一种选择是使用带有类型的Dispatch SourceDISPATCH_SOURCE_TYPE_DATA_OR ,它可以让您重复发布事件并让 libdispatch 为您将它们组合在一起。当你有东西要发布时,你dispatch_source_merge_data习惯于让它知道有新的事情要做。dispatch_source_merge_data如果目标队列(在您的情况下,主队列)忙,多个调用将合并在一起。

于 2013-03-19T16:44:53.230 回答
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 多条合并消息的峰值。

再次感谢您的帮助!

于 2013-03-19T21:38:49.103 回答
2

如果应用程序在重负载下出现沙滩球,那么您已经阻塞了主线程太久,您需要为 UI 更新实施合并策略。如果应用程序仍然对点击有响应,并且没有沙滩球,那么你很好。

于 2013-03-19T15:51:58.133 回答