WatchOS:是否应在主线程上调用扩展的UI更新?

时间:2016-02-07 23:22:23

标签: ios swift watchkit apple-watch watch-os-2

对于iOS应用程序,UI更新是专门从主线程完成的 - 不会这样做从不推荐,并且可能导致意外行为。

在watchOS中,操作系统采用手表扩展程序和应用程序构建 - 作为不同的容器'。通常,从扩展程序调用UI更新,这些更新会在应用程序的容器中更新。

相同的主线程逻辑是否适用于从手表扩展程序更新UI,还是可以从后台调用UI更新?

编辑 - 带来一些清晰度。从应用程序的容器中,UI更新可能应该发生在主线程上(如大多数系统/操作系统中所发生的那样,如下所述)。问题是watchOS是否为我们处理这个问题,即在扩展程序的后台线程上调用UI更新是否会自动发布到应用程序容器的主线程中。

3 个答案:

答案 0 :(得分:4)

Apple的App Programming Guide for watchOS可能是权威指南,但我找不到关于在主线程以外的线程上进行UI更新的参考。

有人会认为,如果从主线程中调用UI更新很重要,那么它会在某处明确说明(就像在App Programming Guide for iOSThreads and Concurrency section中所说的那样):

  

涉及视图,核心动画和许多其他UIKit类的工作   通常必须在应用程序的主线程上发生。有一些例外   对于这个规则 - 例如,基于图像的操作通常可以发生在   背景线程 - 但如果有疑问,假设工作需要发生   在主线上。

尽管如此,以上引用也可以解释为对Watch扩展的UI更新,因为它在iOS上运行。

以上所述,我不相信有任何Apple文档说明这种或那种方式。

这是另一个数据点:Apple的Lister sample code现在包含一个WatchKit扩展,从我对它的简要研究看来,它似乎是调用后台队列(参见ListInfo.swift:34)并更新UI通过调度回主队列(ListsInterfaceController.swift:98)。那里甚至有一条评论说它正在这样做:

  

fetchInfoWithCompletionHandler(_ :)方法在后台调用其完成处理程序   队列,调度回主队列以进行UI更新。

我认为基于上述情况,我会在主线程上进行更新时犯错,除非您确定这样做有性能或其他影响。

答案 1 :(得分:1)

通过技术支持事件联系Apple后,收到的答案和说明如下。

TLDR:使用主线程。

  

所有更新都应该从主线程完成。这一直都是   是UIKit的一般建议和该建议   延伸到watchOS。

     

了解其根本原因可能会有所帮助   需求。请记住,即使是集中沟通   通道序列化更改,尝试时会出现许多问题   从后台线程操纵UI状态。例如,虽然   序列化通道可以防止多个UI命令尝试   要同时执行,它无法控制其中的顺序   不相关的命令将执行。考虑以下两个块:

block 1 {     
  DoUIChange1     
  DoUIChange2     
}

block 2 {     
  DoUIChange3     
  DoUIChange4     
}
     

如果两个块都在主线程上执行,那么实际   命令流是:

DoUIChange1   
DoUIChange2   
DoUIChange3   
DoUIChange4
     

...或

DoUIChange3   
DoUIChange4   
DoUIChange1   
DoUIChange2
     

但是,如果两个块都在自己的线程上执行,甚至更多   可能性开放:

DoUIChange3   
DoUIChange1   
DoUIChange2   
DoUIChange4
     

或..

DoUIChange1   
DoUIChange3   
DoUIChange2   
DoUIChange4
     

或..

DoUIChange1   
DoUIChange3   
DoUIChange4   
DoUIChange2
     

等...

     

毋庸置疑,如果UI代码的数量完全复杂   组合迅速变得巨大,造成意外的UI错误   基本上是不可避免的。

答案 2 :(得分:-1)

您应该始终在主线程上进行UI更新。不这样做会导致UI渲染速度变慢或潜在的应用程序崩溃。这不是特定于iOS或watchOS,因为几乎所有编程语言(C#,Java,C ++等)都要求您在主线程上进行UI更新。

在watchOS 1中,你所建议的内容可能有意义,因为扩展程序在iPhone上并且UI在手表上。在这种情况下,应用程序确实作为两个单独的进程运行,你可以"可能"没有必要调度到主线程的UI更新。但是在watchOS 2中它是不同的。甚至认为watchOS扩展和UI有不同的目标,在watchOS 2中他们不会在手表上作为单独的进程运行(您可以通过在Xcode中查看Apple Watch上的运行进程来验证这一点,并看到每个只有一个应用程序)。仅仅因为它被打包成两个独立的容器(甚至签名不同)并不意味着它们在手表上作为两个独立的进程运行。