对于iOS应用程序,UI更新是专门从主线程完成的 - 不会这样做从不推荐,并且可能导致意外行为。
在watchOS中,操作系统采用手表扩展程序和应用程序构建 - 作为不同的容器'。通常,从扩展程序调用UI更新,这些更新会在应用程序的容器中更新。
相同的主线程逻辑是否适用于从手表扩展程序更新UI,还是可以从后台调用UI更新?
编辑 - 带来一些清晰度。从应用程序的容器中,UI更新可能应该发生在主线程上(如大多数系统/操作系统中所发生的那样,如下所述)。问题是watchOS是否为我们处理这个问题,即在扩展程序的后台线程上调用UI更新是否会自动发布到应用程序容器的主线程中。
答案 0 :(得分:4)
Apple的App Programming Guide for watchOS可能是权威指南,但我找不到关于在主线程以外的线程上进行UI更新的参考。
有人会认为,如果从主线程中调用UI更新很重要,那么它会在某处明确说明(就像在App Programming Guide for iOS中Threads 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上的运行进程来验证这一点,并看到每个只有一个应用程序)。仅仅因为它被打包成两个独立的容器(甚至签名不同)并不意味着它们在手表上作为两个独立的进程运行。