Разработка
Что нового в UIKit после WWDC25
Он продолжает устанавливать стандарт того, каким должен быть императивный фреймворк пользовательского интерфейса, но в то же время — он медленно начал заимствовать идеи из своего декларативного аналога. Интересное время! В iOS 26 UIKit лучше, чем когда-либо.
2019 год стал годом, когда Apple представила SwiftUI. В то время отклики пришли быстро, и они были, ну, немного сенсационными. «UIKit мертв», «Он устарел!», «Теперь бесполезен!»… список можно продолжать. Но вот мы на 25-ом даб-дабе, и в нем анонсировано еще больше улучшений UIKit.
UIKit по-прежнему является фреймворком, поддерживающим iOS, и если вы заглянете под капот достаточно далеко… он поддерживает и SwiftUI. По традиции, давайте посмотрим, что Купертино и друзья™️ приготовили для нас в этом году.
Observable объекты
Начнем наш пост о важных дополнениях UIKit с… разговора о SwiftUI. Как обычно. Observable
сделал SwiftUI просто лучше, и теперь очередь UIKit пожинать те же плоды. Классы UIKit и Observable
теперь работают рука об руку. Это интересно, поскольку общепринятым было мнение, что по мере развития SwiftUI разрыв между ним и UIKit будет увеличиваться.
Вместо этого он сокращается.
Например, посмотрите на изменения взаимодействия анимации с прошлогоднего WWDC, которые позволяют UIKit и SwiftUI координировать анимации.
С Observable
UIKit теперь отслеживает любые изменения в методах обновления, таких как layoutSubviews
. Что следует из этого? Вам не нужно вручную инвалидировать представления и вести учет для их обновления:
import UIKit import Observation @Observable class HitCounter { var hits: Int = 0 } class TestVC: UIViewController { private var counter: HitCounter = .init() private let hitLabel: UILabel = .init(frame: .zero) override func viewDidLoad() { super.viewDidLoad() hitLabel.translatesAutoresizingMaskIntoConstraints = false self.view.addSubview(hitLabel) NSLayoutConstraint.activate([ hitLabel.centerXAnchor.constraint(equalTo: self.view.centerXAnchor), hitLabel.centerYAnchor.constraint(equalTo: self.view.centerYAnchor) ]) DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { self.counter.hits = 10 } } override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() // Dependency wired up self.hitLabel.text = "Hits: \(self.counter.hits)" } } #Preview { TestVC(nibName: nil, bundle: nil) }
Говоря о сокращении разрыва, просто посмотрите на всю SwiftUI-ность в этом небольшом объеме кода. Наблюдаемое отслеживание. Автоматические обновления представления. Предварительный просмотр макросов холста. Вам нравится видеть это.
Здесь UIKit автоматически устанавливает отслеживание наблюдения для свойства hits
. Когда оно изменяется, представление становится недействительным, viewWillLayoutSubviews
запускается снова — и так просто метка обновляется. Опять же, рукопожатия между SwiftUI и UIKit, похоже, становятся крепче с каждым годом, и это только хорошо для экосистемы.
Кроме того, пока мы здесь — что всегда было недостатком SwiftUI? Это то, что большие списки просто не… хорошо листаются. Хотя были внесены изменения под капотом, чтобы улучшить эту ситуацию, общепринятая мудрость тех из нас, кто боролся с этим, была чем-то вроде «Просто оберните UICollectionView!»
Теперь, может быть, это не так верно с новыми оптимизациями длинных списков? В любом случае, теперь это проще сделать. Тот же метод выше распространяется на UIListContentConfiguration
, что означает, что ячейки в представлениях коллекций также могут автоматически обновляться из моделей Observable
:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "customcell", for: indexPath) let myModel = store.model(at: indexPath) cell.configurationUpdateHandler = { cell, state in var content = UIListContentConfiguration.cell() content.text = myModel.name cell.contentConfiguration = content } return cell }
Что еще лучше, вы можете выполнить обратное развертывание этого в iOS 18, добавив ключ UIObservationTrackingEnabled
в файл info.plist.
Обновление свойств
Новый метод жизненного цикла в UIView и UIViewController!? Какой это год?
Мне нравится. Встречайте updateProperties()
, который вызывается прямо перед layoutSubviews()
. Как и многие функции жизненного цикла, вы можете вручную вызвать его — setNeedsUpdateProperties()
. Итак, что он делает и когда его использовать?
Короче говоря, вы можете применять стили или гидратировать детали, связанные с представлением, из моделей и других связанных задач, не прибегая к полной перестройке макета. Вам нужно обновить одну маленькую вещь? Вам не обязательно обновлять всю иерархию представлений, но так все работало до сих пор. Главное, что новый метод работает независимо от других методов макета (например, layoutSubviews()
).
На верхнем уровне формирование макета сверху вниз теперь выглядит так:
- Обновление признаков
- Обновление свойств
- Подпредставления макета
Apple хочет разделить то, как вы думаете о разметке представлений сейчас, то есть работа по обновлению свойств представления из данных вашего приложения может выполняться в своем собственном месте (updateProperties()
), а работа логики макета может выполняться в другом месте (layoutSubviews()
):
// Before, these two jobs were typically handled in the same place. // Now, they can occur independently class MyVC: UIViewController { override func updateProperties() { super.updateProperties() myLabel.text = myModel.text } override func layoutSubviews() { super.layoutSubviews() myLabel.setFrameDimensions() } }
Отказ от обновлений анимации
Это изменение просто супер. Ранее традиционным UIKitter-ам приходилось менять что-то в блоке анимации, а затем сообщать UIKit, чтобы он аннулировал представление, чтобы снова его разместить:
// Before UIView.animate { myModel.confirmationColor = validation.isValid ? .green : .red confirmationView.layoutIfNeeded() }
У вас тут две задачи — обновить состояние и сказать вашему представлению отразить его. Непристойный рабочий процесс в 2025 году. Так что, если вы работаете с observable моделями, теперь вы можете пропустить весь этот танец «Эй, я обновил свойство, пожалуйста, перерисуйте что-нибудь в этом блоке анимации»:
UIView.animate(options: .flushUpdates) { myModel.confirmationColor = validation.isValid ? .green : .red }
Благодаря автоматическому отслеживанию изменений, UIKit теперь просто позаботится об этом за вас. Нам даже не нужно ссылаться на confirmedView
, UIKit знает, что это зависит от confirmedColor
в myModel
.
Это работает даже за пределами Observable
объектов. Вы даже можете настраивать анимации constraint, используя ту же опцию .flushUpdates
. Если вы вручную удерживали ссылки на NSLayoutConstraint
во имя простого смещения метки на 20 пунктов вниз, ну… я думаю, что теперь вы можете отказаться от этого.
Бонусы
- Множество новых API для поддержки изменений
UIMenu
в iPadOS. - Настройки Inspector API, особенно в отношении их использования в контроллере разделенного представления.
- Теперь команда Key позволяет вам поддерживать, будет ли команда выполняться повторно или нет,
keyCommand.repeatBehavior = .nonRepeatable
. - Вы можете размещать сцены SwiftUI в приложениях UIKit через протокол
UIHostingSceneDelegate
. Идеально подходит для постепенного внедрения SwiftUI или использования иммерсивных пространств, которые есть только в фреймворке. - HDR распространяется на цвета, а не только на медиа, что означает, что вы можете накручивать все при создании экземпляров
UIColor
и предпочитать выбор HDR в палитре цветов. - Символы имеют анимации
.drawOff
и.drawOn
. Это приятный штрих.
Кроме того, время идет вперед. Таким образом, некоторые старые добрые друзья были обречены на устаревание. API UIApplication
устарели в пользу их аналогов UIScene
, например. Честно говоря, я думал, что это уже сделано. Так что, если вы не приняли мир UIScene
, ну… вам, вероятно, стоит это сделать.
Что я могу сказать? Еще один год, еще один UIKit. Как и в предыдущие годы, он стал намного лучше. Он продолжает устанавливать стандарт того, каким должен быть императивный фреймворк пользовательского интерфейса, но в то же время — он медленно начал заимствовать идеи из своего декларативного аналога. Интересное время! В iOS 26 UIKit лучше, чем когда-либо.
До следующих встреч!
-
Видео и подкасты для разработчиков3 недели назад
Пагинация: от идеи до реализации
-
Новости3 недели назад
Видео и подкасты о мобильной разработке 2025.25
-
Видео и подкасты для разработчиков3 недели назад
История, принципы и концепции библиотеки навигации Decompose
-
Исследования3 недели назад
Bidease: мобильный маркетинг 2025 — баланс AI, удержания и конфиденциальности