【问题标题】:Should I use a background thread for my UI actions?我应该为我的 UI 操作使用后台线程吗?
【发布时间】:2010-09-24 12:29:59
【问题描述】:

背景

  • 我有一个显示 TrainingGroup 实体的 NSOutlineView

  • 每个 TrainingGroup 代表本地机器上的一个文件夹。

  • NSOutlineView 绑定到一个NSTreeController,其获取谓词为IsTrained == 0

  • 每个 TrainingGroup 都可以分配给一个项目。

  • 每个 TrainingGroup 都有许多 TrainingEntries 显示该文件的工作时间。

  • 将 TrainingGroup 分配给项目时,IsTrained 设置为 YES

  • 在分配给项目时,所有后代也被分配给该项目,并且它们的 IsTrained 属性也设置为 YES

  • 项目列绑定到projectTopLevel 属性。

示例

整棵树是这样的:

Name                       Project              IsTrained
Users                      nil                  NO
  John                     nil                  NO              
    Documents              nil                  NO
      Acme Project         Acme Project         YES
        Proposal.doc       Acme Project         YES
          12:32-12:33      Acme Project         YES
          13:11-13:33      Acme Project         YES
          ... etc
        Budget.xls         Acme Project         YES
      Big Co Project       Big Co Project       YES
        Deadlines.txt      Big Co Project       YES
        Spec.doc           Big Co Project       YES
      New Project          nil                  NO
        StartingUp.doc     nil                  NO
      Personal Stuff       Personal             YES
        MyTreehouse.doc    Personal             YES
    Movies                 nil                  NO
      Aliens.mov           nil                  NO
      StepMom.mov          nil                  NO

NSOutlineView 只会看到这个:

Users                      nil                  NO
  John                     nil                  NO              
    Documents              nil                  NO
      New Project          nil                  NO
        StartingUp.doc     nil                  NO
    Movies                 nil                  NO
      Aliens.mov           nil                  NO
      StepMom.mov          nil                  NO

如果您将电影分配给个人,则视图现在如下所示:

Users                      nil                  NO
  John                     nil                  NO              
    Documents              nil                  NO
      New Project          nil                  NO
        StartingUp.doc     nil                  NO

代码

TrainingGroup.m

-(void)setProjectTopLevel:(JGProject *)projectToAssign {
    [self setProjectForSelf:projectToAssign];
    [self setProjectForChildren:projectToAssign];
}

-(void)setProjectForSelf:(JGProject *)projectToAssign {
    [self setProject:projectToAssign];
}

-(void)setProjectForChildren:(JGProject *)projectToAssign {
    for (TrainingGroup *thisTrainingGroup in [self descendants]) {
        [thisTrainingGroup setProject:projectToAssign];
        if(projectToAssign != nil) {
            [thisTrainingGroup setIsTrainedValue:YES];
        } else {
            [thisTrainingGroup setIsTrainedValue:NO];
        }
        // Other code updating rules.
    }
}

-(JGProject *)projectTopLevel {
    return [self project];
}

-(NSSet *)untrainedChildren {
    // Code that loops through all children returning those
    // whose isTrained is NO. Omitted for brevity.
}

问题

正如你在上面看到的,我目前正在主线程上运行所有的项目分配代码。

当每个文件夹下有数百个时间条目时,我的应用程序变得无响应。

可能的解决方案

1 模态进度条

方法

  • 在单独上下文中的后台线程上运行项目分配。
  • 完成后使用标准 Core Data 合并到主上下文中。
  • 在项目分配完成之前,模式表会阻止任何进一步的活动。

  • 用户可以立即获得有关正在发生的事情的反馈。
  • 应用保持响应。

坏人

  • 在当前分配完成之前,用户不能做任何事情。

2 非模态微调器

方法

  • 在单独上下文中的后台线程上运行项目分配。
  • 完成后使用标准 Core Data 合并到主上下文中。
  • 在训练组旁边显示进度微调器,表示它很忙。
  • 完成分配后,训练组将从视图中消失。

  • 用户可以在处理最后一个操作时执行其他操作
  • 应用程序保持响应。有点。见下文。

坏人

  • 在测试中,当后台上下文合并到主上下文中时,我发现最多冻结 3 秒。
  • 视图可能会在用户执行其他操作时更新,这可能很烦人。
  • 撤消将难以实施。

3 隐藏

方法

  • 以上,除了培训组在分配时被删除,并且在分配完成之前设置为“进行中”。

好与坏

  • 与上述相同,但训练组的顺序仍可预测。
  • 在合并回主上下文时仍然大面积冻结。

4 提高性能

方法

  • 保持代码原样,在主线程上运行。
  • 提高性能,即使有数千个条目,视图也最多只能冻结半秒

  • 应用保持响应。
  • 撤消仍然很容易。
  • 架构依然简单。

坏人

  • 据我了解,违反 Apple 的建议 - 不应在主线程上进行密集处理
  • 我能获得足够好的性能吗?未知。

我的问题

据我所知,以上选项都不理想。

1.哪个是最佳选择?

2。还有其他选择吗?

3.我可以改进我的方法吗?

【问题讨论】:

  • +1 详细而漂亮的问题

标签: multithreading cocoa performance core-data nsoutlineview


【解决方案1】:
  1. 我会在后台线程上更新(第 2 条)
  2. 您可以随时在窗口的某些部分禁用用户输入,并显示加载消息。
  3. 说起来很简单 - 浏览所有代码,并确保您进行所需的调用次数最少,并且不调用任何不必要的函数。您还可以在单​​独的线程上运行一些持久的操作,然后在操作完成时收到通知,这样您就可以在操作进行时处理其他事情。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-02
    • 2012-06-24
    • 1970-01-01
    • 1970-01-01
    • 2010-11-02
    相关资源
    最近更新 更多