Подтвердить что ты не робот

WatchOS: Должны ли вызываться обновления UI из расширения в основном потоке?

Для приложений iOS обновление пользовательского интерфейса выполняется исключительно из основного потока - не делать этого никогда не рекомендуется и может привести к неожиданному поведению.

В watchOS, ОС структурирована с расширением часов, а приложение - как разные "контейнеры". Обычно обновления пользовательского интерфейса вызывают из расширения, и они обновляют что-то в контейнере приложения.

Используется ли одна и та же логика основного потока для обновления пользовательского интерфейса из расширения часового пояса или могут быть вызваны обновления пользовательского интерфейса из фона?


Изменить - чтобы внести ясность. Из контейнера приложений обновления пользовательского интерфейса, вероятно, должны произойти в основном потоке (как это происходит в большинстве систем/ОС, как указано ниже). Вопрос в том, действительно ли watchOS обрабатывает это для нас, т.е. Будет ли вызов обновления пользовательского интерфейса в фоновом потоке расширения автоматически отправляться в основной поток контейнера приложений для нас.

4b9b3361

Ответ 1

После контакта с Apple через Инцидент технической поддержки полученный ответ и пояснения ниже.

TL;DR: используйте основной поток.

Все обновления должны быть сделаны из основного потока. Это всегда были общей рекомендацией для UIKit и этой рекомендации распространяется на watchOS.

Возможно, было бы полезно понять основную причину этого требование. Имейте в виду, что даже при централизованном канал для сериализации изменений, многие проблемы возникают, когда вы пытаетесь манипулировать состоянием пользовательского интерфейса из фоновых потоков. Например, хотя канал сериализации может предотвратить попытки нескольких команд пользовательского интерфейса для одновременного выполнения, он не может контролировать порядок, в котором выполняются несвязанные команды. Рассмотрим следующие 2 блока:

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 в основном неизбежны.

Ответ 2

Apple Руководство по программированию приложений для watchOS, вероятно, будет окончательным руководством, но я не могу найти здесь никакой ссылки относительно того, как делать обновления пользовательского интерфейса для потоков других чем основной поток.

Можно подумать, что если было бы важно, чтобы обновления UI вызывались из основного потока, то он явно указывал бы, что где-то (как это происходит в Руководство по программированию приложений для iOS, в разделе Темы и раздел Concurrency):

Работа с представлениями, Core Animation и многими другими классами UIKit обычно должны встречаться в основной теме приложения. Есть некоторые исключения к этому правилу - например, манипуляции с изображениями могут часто возникать на фоновые потоки, но если вы сомневаетесь, предположите, что работа должна произойти на основной теме.

Хотя приведенная выше цитата может быть истолкована как верность обновлениям пользовательского интерфейса к расширению Watch также, поскольку это работает на iOS.

Все выше сказанное, я не верю, что есть какая-либо документация Apple, заявляющая так или иначе.

Здесь другая точка данных: Apple Пример кода Lister теперь включает расширение WatchKit, и из моего краткого изучения его, похоже, (см. ListInfo.swift: 34) и обновление пользовательского интерфейса путем отправки обратно в основную очередь (ListInterfaceController.swift: 98). Там даже комментарий там говорит, что он это делает:

Метод fetchInfoWithCompletionHandler (_:) вызывает свой обработчик завершения на фоне очереди, отправьте обратно в основную очередь, чтобы сделать обновления пользовательского интерфейса.

Я думаю, основываясь на вышесказанном, я бы ошибался на стороне обновлений в основном потоке, если вы не определяете, что есть производительность или другие последствия этого.

Ответ 3

Вы всегда должны делать обновления пользовательского интерфейса в основном потоке. Невыполнение этого приведет к замедлению отображения пользовательского интерфейса или потенциальному сбою приложения. Это не относится к iOS или watchOS, так как почти все языки программирования (С#, Java, С++ и т.д.) Требуют, чтобы вы делали обновления пользовательского интерфейса в основном потоке.

В watchOS 1 то, что вы предлагаете, может иметь смысл, поскольку расширение было на iPhone, и пользовательский интерфейс был на часах. В этом случае приложение выполнялось как два отдельных процесса, и вам "Might" не нужно было отправлять основной поток для обновлений пользовательского интерфейса. Но в watchOS 2 это другое. Даже если у watchOS-расширения и у UI есть разные цели, в watchOS 2 они не работают как отдельные процессы на часах (вы можете проверить это, просмотрев запущенные процессы на ваших яблочных часах в Xcode и посмотрите, что для каждого приложения есть только один), Просто потому, что он упакован как два отдельных контейнера (и даже подписаны по-разному) не означает, что они работают как два отдельных процесса на часах.