我应该为我的UI操作使用后台线程吗? [英] Should I use a background thread for my UI actions?

查看:80
本文介绍了我应该为我的UI操作使用后台线程吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景




  • 我有一个 NSOutlineView Training Group群组实体。


  • 每个TrainingGroup代表本机上的资料夹。


  • NSOutlineView 绑定到 NSTreeController ,并且fetch谓词 IsTrained == 0


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



  • 当TrainingGroup指定给某个项目时, IsTrained 设置为 YES


  • 分配给项目时,所有后代也分配到该项目,并且 IsTrained 属性也设置为 YES


  • 项目列绑定到 projectTopLevel 属性。




示例



整个树如下所示:

 名称项目IsTrained 
用户nil NO
John nil NO
文档nil NO
Acme项目Acme项目YES
提案。 doc Acme项目YES
12:32-12:33 Acme项目YES
13:11-13:33 Acme项目YES
... etc
Budget.xls Acme Project YES
Big Co项目Big Co项目YES
Deadlines.txt Big Co项目YES
Spec.doc Big Co项目YES
新项目nil NO
StartingUp.doc nil NO
个人资料个人YES
MyTreehouse.doc个人是
电影nil NO
Aliens.mov nil NO
StepMom.mov nil NO

而NSOutlineView只会看到:

 用户nil NO 
John nil NO
文档nil NO
新项目nil NO
StartingUp.doc nil NO
电影nil NO
外星人。 mov nil NO
StepMom.mov nil NO

如果您将Movies指定给Personal,现在看起来像这样:

 用户nil NO 
John nil NO
文档nil NO
新项目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];
}
//其他代码更新规则。
}
}

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

- (NSSet *)untrainedChildren {
//循环遍历所有返回
//的子节点的代码,其isTrained为NO。省略省略。
}



问题





当我在每个文件夹下有数百个时间条目时,我的应用程序



方法




  • 在后台主题执行专案作业

  • 完成后,使用标准Core Data合并到主上下文中。

  • 模态工作表阻止任何进一步的活动,直到项目分配完成。






  • 用户即时获得有关发生的反馈。

  • 应用程式保持回应状态。



p>


  • 在当前作业完成之前,用户无法执行任何操作。


b $ b

2非模态微调器




  • 完成后,使用标准Core Data合并到主上下文中。

  • 完成分配后,训练组将从视图中消失。







    • 应用程式保持回应状态。 Kinda。








  • 在测试中,当背景上下文合并到主上下文中时,我看到冻结最多3秒。

  • 视图可以在中间更新

  • 撤消将难以实施。



  • 3隐藏



      >
    • 上面,除非训练组在assign中被删除,并且设置为进行中,直到分配完成。



    好与坏




    • 同上,除了训练组的排序



  • 4改善效果





    • 提高效果,即使有数千个条目,视图只会冻结半秒钟的最大值









    • b $ b




      • 据我理解,根据苹果的建议,密集处理不应

      • 我可以获得足够的性能吗?未知。



      我的问题



      据我所见,的选项是理想的。



      1。哪个是最好的选择?



      2。还有其他选项吗?



      3。

      解决方案


      1. 我会在背景上更新

      2. 您可以随时禁用窗口部分的用户输入,并显示加载消息。

      3. 遍历所有代码,并确保您所需的调用次数最少,并且不调用任何不必要的函数。您还可以在单​​独的线程上运行一些持久的操作,然后在操作完成时收到通知,以便在操作继续时处理其他内容。


      Background

      • I've got an NSOutlineView that shows TrainingGroup entities.

      • Each TrainingGroup represents a folder on the local machine.

      • The NSOutlineView is bound to an NSTreeController with a fetch predicate of IsTrained == 0

      • Each TrainingGroup can be assigned to a project.

      • Each TrainingGroup has many TrainingEntries that show a time worked on that file.

      • When the TrainingGroup is assigned to a project, the IsTrained is set to YES.

      • On assign to a project, all descendants are also assigned to that project and their IsTrained property is set to YES too.

      • Project column is bound to projectTopLevel property.

      Example

      The whole tree looks like this:

      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
      

      And the NSOutlineView would only see this:

      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
      

      If you assigned Movies to Personal, the view would now look like this:

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

      Code

      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.
      }
      

      The Problem

      As you can see above, I'm running all the project assignment code on the main thread currently.

      When there are hundreds of time entries under each folder, my app becomes unresponsive.

      Possible Solutions

      1 Modal progress bar

      The Approach

      • Run project assignment on a background thread in separate context.
      • Use standard Core Data merge into main context when finished.
      • A modal sheet blocks any further activity until the project assignment has finished.

      The Good

      • The user gets immediate feedback on what's happening.
      • The app remains responsive.

      The Bad

      • User can't do anything until the current assignment has finished.

      2 Non Modal Spinner

      The Approach

      • Run project assignment on a background thread in separate context.
      • Use standard Core Data merge into main context when finished.
      • Show progress spinner alongside training group, indicating it's busy.
      • On finish assigning, the training group disappears from the view.

      The Good

      • The user can do other stuff whilst their last action is being processed
      • The app remains responsive. Kinda. See below.

      The Bad

      • In tests, I've seen a freeze of up to 3 seconds when the background context is merged into the main context.
      • The view could update in the middle of the user doing something else, which might be annoying.
      • Undo would be hard to implement.

      3 Hide

      The Approach

      • Above, except the training group is removed on assign, and is set to be "In Progress" until assign has finished.

      Good and Bad

      • Same as above, except the ordering of the training groups would remain predicatable.
      • Still large freeze on merge back into main context.

      4 Improve performance

      The Approach

      • Keep the code as it is, running on the main thread.
      • Improve performance so even with thousands of entries, the view only freezes for half a second max

      The Good

      • App remains responsive.
      • Undo remains easy.
      • Architecture remains simple.

      The Bad

      • As I understand it, against Apple's recommendations - intensive processing should not be done on the main thread
      • Can I get the performance good enough? Unknown.

      My Questions

      As far as I can see, none of the options above are ideal.

      1. Which is the best option?

      2. Are there any other options?

      3. What could I improve about my approach?

      解决方案

      1. I would update on a background thread (No. 2)
      2. You could always disable user input on sections of your window, and display a loading message.
      3. Simple to say - go through all your code, and make sure you are making the least number of calls required, and that you do not call any unnecessary functions. You could also run some long lasting operations on separate threads, and then get notified when the action finishes, so you can process other things while the operation goes on.

      这篇关于我应该为我的UI操作使用后台线程吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆