Приветствую вас, жители Хабра и все интересующиеся разработкой под IOS. На связи Анна Жаркова, Senior iOS/Android разработчик компании Usetech
Сегодня мы поговорим о тех изменениях и новшествах, которые нам представляет Apple на WWDC 2020. А именно про доработанную и даже переработанную версию фреймворка SwiftUI.
Эта технология для декларативной разработки приложений была представлен в прошлом году на WWDC 2019. Если вы с ней еще не работали, то рекомендую заглянуть сюда
Итак. Apple и их инженеры внимательно весь этот год следили за обзорами, статьями, решениями и комментариями от разработчиков-энтузиастов. В конце видео «What's new in SwiftUI» они выражают благодарность всем неравнодушным за помощь.
Теперь SwiftUI позиционируется как полноценный инструмент для разработки под разные платформы (от watchOS до macOS):
![](https://webcf.waybackmachine.org/web/20220427050019im_/https://habrastorage.org/r/w1560/webt/du/nh/vu/dunhvuvnryo4i2yqw7187tqimp0.png)
Причем разработку под разные платформы можно вести в едином проекте. В Xcode 12 появляется шаблон для упрощения создания такого решения:
![](https://webcf.waybackmachine.org/web/20220427050019im_/https://habrastorage.org/r/w1560/webt/wl/u2/g8/wlu2g8doeqfmm7i2airnzx0wih0.png)
Система создаст проект с Shared-блоком и платформенными таргетами, где вы можете добавлять что-то специфичное для конкретной платформы:
![](https://webcf.waybackmachine.org/web/20220427050019im_/https://habrastorage.org/r/w1560/webt/dg/ui/ao/dguiaodpdzfhm4_cve-4dvypmb0.png)
Может показаться, что где-то это вы уже видели в Kotlin Multiplatform. Что ж, видимо, в этом году тренд на явное заимствование у конкурентов.
Итак, чтобы обеспечить функционирование на всех поддерживаемых платформах, инженеры Apple проделали огромную работу.
Расширили поддержку контролов. Теперь практически все контролы UIKit портированы на SwiftUI
![](https://webcf.waybackmachine.org/web/20220427050019im_/https://habrastorage.org/r/w1560/webt/hg/e-/er/hge-erzxainfznriyxzzvdpsqka.png)
Немаловажно, что в SwiftUI появляется аналог UICollectionView — LazyVGrid/LazyHGrid, использующий GridItem:
![](https://webcf.waybackmachine.org/web/20220427050019im_/https://habrastorage.org/r/w1560/webt/tj/yv/yq/tjyvyq8x2qehjqv2yov6nas2o8w.png)
Кстати, в процессе работы над новым контролом Apple оптимизировали работу на UITableView/UICollectionView в UIKit.
Появились средства поддержки адаптивности в настройке параметров UI (размеры контролов, шрифт, отступы и т.п). Например, атрибут @ScaledMetric у настраиваемой величины:
![](https://webcf.waybackmachine.org/web/20220427050019im_/https://habrastorage.org/r/w1560/webt/-y/6j/vo/-y6jvowpqbs2dwswuouq36mtahc.png)
Также расширили поддержку фреймворков на SwiftUI.
![](https://webcf.waybackmachine.org/web/20220427050019im_/https://habrastorage.org/r/w1560/webt/p8/xe/0d/p8xe0dnntxm0pyanrxxeklj_efk.png)
Теперь можно использовать их вместе с ViewState:
Добавили поддержку Document Based Apps, Widgets, App Clips. Последние 2 являются новыми фичами iOS SDK 14. Виджеты — практически аналог того, что было в Android.
Туториалы и видео работы с ними будут представлены вот-вот на WWDC 2020.
Появились и более масштабные изменения, связанные с производительностью, архитектурным подходом к созданию приложений и декларативным конструктором:
1. Оптимизирована работа с памятью. Memory Performance.
Это глобальное изменение для Swift 5.3 в целом. Переход внутри на структуры позволяет использовать передачу по значению вместо ссылок, тем самым сокращая размер кучи (heap), размер бинарников и времени на компиляцию.
![](https://webcf.waybackmachine.org/web/20220427050019im_/https://habrastorage.org/r/w1560/webt/v7/tx/fl/v7txflgrvlrjddwghhpsfvtrvxi.png)
Кстати, некоторые контролы в самом SwiftUI стали использовать Lazy подход. Например, те же списки и LazyVGrid/LazyHGrid(аналог UICollectionView). По идее, это должно убрать проблему с инициализацией View сразу. Однако, пока еще ничего не было сказано про NavigationLink… .
2. Использование DSL внутри блоков ViewBuilder.
Ура, теперь мы можем добавить if/else или switch-case в декларативных блоках в своих целях. Например, сделать фабрику Child View внутри родительского View. Или внутри NavigationView.
![](https://webcf.waybackmachine.org/web/20220427050019im_/https://habrastorage.org/r/w1560/webt/r8/yg/uh/r8yguhghgm5janwtjltpjuuap48.png)
Это очень круто.
Также теперь можно проверять условие по @PropertyWrapper внутри блока:
3. Теперь можно создать приложение 100% на компонентах SwiftUI.
Да-да. Для этого Apple придумали, как обойтись без AppDelegate, SceneDelegate и UIHostingViewController.
С помощью аннотации main и протоколов App, Scene вы сможете этого достичь:
main сигнализирует, что это новая входная точка вашего приложения. Реализация протокола App обязательна. Обратите внимание на тип свойства body структуры App. В приложении может быть одна или несколько так называемых сцен, каждая из которых реализует протокол Scene. У каждой сцены есть свой root View и свой жизненный цикл. Если вы хотите использовать несколько сцен (как, например, в многооконном приложении), то необходимо поставить у body атрибут SceneBuilder. По сути это механизм инкапсуляции UISceneDelegate и его логики.
WindowGroup используется для создания единого полноразмерного экрана, как и UIWindow/UIWindowScene.
Однако, мы помним, что SwiftUI — это надстройка над UIKit. И UIKit остался внутри. Если мы запустим даже вот такое шаблонное приложение, то в иерархии View мы увидим:
![](https://webcf.waybackmachine.org/web/20220427050019im_/https://habrastorage.org/r/w1560/webt/8o/sz/kz/8oszkzjav2bu2vz2osxpskekbai.png)
И UIHostingViewController на месте, и UIWindowScene. Но внутри. Да, для инициализации это очень упрощает работу. Но продумали ли они решение, чтобы не пришлось возвращать в приложение UISceneDelegate с явным заданием всей навигационной структуры.
Отслеживание lifecycle сцены сокращается до метода:
Вот так предлагают использовать данный метод для отслеживания перехода приложения в фоновое состояние:
4. Изменение предлагаемой архитектуры для SwiftUI.
Видео-презентации еще не было, но судя по документации на сайте, это уже не MVVM, а MVI или Redux:
![](https://webcf.waybackmachine.org/web/20220427050019im_/https://habrastorage.org/r/w1560/webt/k6/jx/px/k6jxpxica4d1hvfu2vxacggl3tm.png)
Да-да, обратите внимание на изменение связей.
Что ж, это еще одно подтверждение тренда на заимствование у конкурентов. Пока Google вдохновляются SwiftUI для новой версии JetPack Compose, Apple вдохновляются предложениями Google. Ну а факт заимствования у энтузиастов Apple и не скрывали. Статей, посвященных использованию именно Redux/MVI с SwiftUI, в сети очень много на разных языках еще с прошлого года: ссылка.
Как пример.
И это, конечно, далеко не все. Сессия в самом разгаре, интересное еще впереди. Но в принципе этого уже достаточно, чтобы понять, что меняется многое.
Не расстраивайтесь, если у вас были планы на работу с несовершенствами SwiftUi в прошлой реализации. По крайней мере, вы знаете базу и сможете перестроиться на новую версию.
В общем, присоединяйтесь к WWDC 2020. И ждите новых статей на Хабре)
Сегодня мы поговорим о тех изменениях и новшествах, которые нам представляет Apple на WWDC 2020. А именно про доработанную и даже переработанную версию фреймворка SwiftUI.
Эта технология для декларативной разработки приложений была представлен в прошлом году на WWDC 2019. Если вы с ней еще не работали, то рекомендую заглянуть сюда
Итак. Apple и их инженеры внимательно весь этот год следили за обзорами, статьями, решениями и комментариями от разработчиков-энтузиастов. В конце видео «What's new in SwiftUI» они выражают благодарность всем неравнодушным за помощь.
Теперь SwiftUI позиционируется как полноценный инструмент для разработки под разные платформы (от watchOS до macOS):
![](https://webcf.waybackmachine.org/web/20220427050019/https://habrastorage.org/webt/du/nh/vu/dunhvuvnryo4i2yqw7187tqimp0.png)
Причем разработку под разные платформы можно вести в едином проекте. В Xcode 12 появляется шаблон для упрощения создания такого решения:
![](https://webcf.waybackmachine.org/web/20220427050019/https://habrastorage.org/webt/wl/u2/g8/wlu2g8doeqfmm7i2airnzx0wih0.png)
Система создаст проект с Shared-блоком и платформенными таргетами, где вы можете добавлять что-то специфичное для конкретной платформы:
![](https://webcf.waybackmachine.org/web/20220427050019/https://habrastorage.org/webt/dg/ui/ao/dguiaodpdzfhm4_cve-4dvypmb0.png)
Может показаться, что где-то это вы уже видели
Итак, чтобы обеспечить функционирование на всех поддерживаемых платформах, инженеры Apple проделали огромную работу.
Расширили поддержку контролов. Теперь практически все контролы UIKit портированы на SwiftUI
![](https://webcf.waybackmachine.org/web/20220427050019/https://habrastorage.org/webt/hg/e-/er/hge-erzxainfznriyxzzvdpsqka.png)
Немаловажно, что в SwiftUI появляется аналог UICollectionView — LazyVGrid/LazyHGrid, использующий GridItem:
![](https://webcf.waybackmachine.org/web/20220427050019/https://habrastorage.org/webt/tj/yv/yq/tjyvyq8x2qehjqv2yov6nas2o8w.png)
Кстати, в процессе работы над новым контролом Apple оптимизировали работу на UITableView/UICollectionView в UIKit.
Появились средства поддержки адаптивности в настройке параметров UI (размеры контролов, шрифт, отступы и т.п). Например, атрибут @ScaledMetric у настраиваемой величины:
![](https://webcf.waybackmachine.org/web/20220427050019/https://habrastorage.org/webt/-y/6j/vo/-y6jvowpqbs2dwswuouq36mtahc.png)
Также расширили поддержку фреймворков на SwiftUI.
![](https://webcf.waybackmachine.org/web/20220427050019/https://habrastorage.org/webt/p8/xe/0d/p8xe0dnntxm0pyanrxxeklj_efk.png)
Теперь можно использовать их вместе с ViewState:
Map(coordinateRegion: <#T##Binding<MKCoordinateRegion>#>)
Добавили поддержку Document Based Apps, Widgets, App Clips. Последние 2 являются новыми фичами iOS SDK 14. Виджеты — практически аналог того, что было в Android.
Туториалы и видео работы с ними будут представлены вот-вот на WWDC 2020.
Появились и более масштабные изменения, связанные с производительностью, архитектурным подходом к созданию приложений и декларативным конструктором:
1. Оптимизирована работа с памятью. Memory Performance.
Это глобальное изменение для Swift 5.3 в целом. Переход внутри на структуры позволяет использовать передачу по значению вместо ссылок, тем самым сокращая размер кучи (heap), размер бинарников и времени на компиляцию.
![](https://webcf.waybackmachine.org/web/20220427050019/https://habrastorage.org/webt/v7/tx/fl/v7txflgrvlrjddwghhpsfvtrvxi.png)
Кстати, некоторые контролы в самом SwiftUI стали использовать Lazy подход. Например, те же списки и LazyVGrid/LazyHGrid(аналог UICollectionView). По идее, это должно убрать проблему с инициализацией View сразу. Однако, пока еще ничего не было сказано про NavigationLink… .
2. Использование DSL внутри блоков ViewBuilder.
Ура, теперь мы можем добавить if/else или switch-case в декларативных блоках в своих целях. Например, сделать фабрику Child View внутри родительского View. Или внутри NavigationView.
![](https://webcf.waybackmachine.org/web/20220427050019/https://habrastorage.org/webt/r8/yg/uh/r8yguhghgm5janwtjltpjuuap48.png)
Это очень круто.
Также теперь можно проверять условие по @PropertyWrapper внутри блока:
@State private var isVisible = true
if isVisible == true {
Text("Hello") // Only rendered when isVisible is true.
}
3. Теперь можно создать приложение 100% на компонентах SwiftUI.
Да-да. Для этого Apple придумали, как обойтись без AppDelegate, SceneDelegate и UIHostingViewController.
С помощью аннотации main и протоколов App, Scene вы сможете этого достичь:
@main
struct testmultiplatformApp: App {
@SceneBuilder var body: some Scene {
WindowGroup {
MailViewer()
}
Settings {
SettingsView()
}
}
}
main сигнализирует, что это новая входная точка вашего приложения. Реализация протокола App обязательна. Обратите внимание на тип свойства body структуры App. В приложении может быть одна или несколько так называемых сцен, каждая из которых реализует протокол Scene. У каждой сцены есть свой root View и свой жизненный цикл. Если вы хотите использовать несколько сцен (как, например, в многооконном приложении), то необходимо поставить у body атрибут SceneBuilder. По сути это механизм инкапсуляции UISceneDelegate и его логики.
WindowGroup используется для создания единого полноразмерного экрана, как и UIWindow/UIWindowScene.
Однако, мы помним, что SwiftUI — это надстройка над UIKit. И UIKit остался внутри. Если мы запустим даже вот такое шаблонное приложение, то в иерархии View мы увидим:
![](https://webcf.waybackmachine.org/web/20220427050019/https://habrastorage.org/webt/8o/sz/kz/8oszkzjav2bu2vz2osxpskekbai.png)
И UIHostingViewController на месте, и UIWindowScene. Но внутри. Да, для инициализации это очень упрощает работу. Но продумали ли они решение, чтобы не пришлось возвращать в приложение UISceneDelegate с явным заданием всей навигационной структуры.
Отслеживание lifecycle сцены сокращается до метода:
public func onChange<V>(of value: V, perform action: @escaping (V) -> Void) -> some Scene where V : Equatable
Вот так предлагают использовать данный метод для отслеживания перехода приложения в фоновое состояние:
///
/// Use this modifier to trigger a side effect when a value changes, like
/// the value associated with an ``SwiftUI/Environment`` key or a
/// ``SwiftUI/Binding``. For example, you can clear a cache when you notice
/// that a scene moves to the background:
///
/// struct MyScene: Scene {
/// @Environment(\.scenePhase) private var scenePhase
/// @StateObject private var cache = DataCache()
///
/// var body: some Scene {
/// WindowGroup {
/// MyRootView()
/// }
/// .onChange(of: scenePhase) { newScenePhase in
/// if newScenePhase == .background {
/// cache.empty()
/// }
/// }
/// }
/// }
///
/// The system calls the `action` closure on the main thread, so avoid
/// long-running tasks in the closure. If you need to perform such tasks,
/// dispatch to a background queue:
///
/// .onChange(of: scenePhase) { newScenePhase in
/// if newScenePhase == .background {
/// DispatchQueue.global(qos: .background).async {
/// // ...
/// }
/// }
/// }
///
/// The system passes the new value into the closure. If you need the old
/// value, capture it in the closure.
///
4. Изменение предлагаемой архитектуры для SwiftUI.
Видео-презентации еще не было, но судя по документации на сайте, это уже не MVVM, а MVI или Redux:
![](https://webcf.waybackmachine.org/web/20220427050019/https://habrastorage.org/webt/k6/jx/px/k6jxpxica4d1hvfu2vxacggl3tm.png)
Да-да, обратите внимание на изменение связей.
Что ж, это еще одно подтверждение тренда на заимствование у конкурентов. Пока Google вдохновляются SwiftUI для новой версии JetPack Compose, Apple вдохновляются предложениями Google. Ну а факт заимствования у энтузиастов Apple и не скрывали. Статей, посвященных использованию именно Redux/MVI с SwiftUI, в сети очень много на разных языках еще с прошлого года: ссылка.
Как пример.
И это, конечно, далеко не все. Сессия в самом разгаре, интересное еще впереди. Но в принципе этого уже достаточно, чтобы понять, что меняется многое.
Не расстраивайтесь, если у вас были планы на работу с несовершенствами SwiftUi в прошлой реализации. По крайней мере, вы знаете базу и сможете перестроиться на новую версию.
В общем, присоединяйтесь к WWDC 2020. И ждите новых статей на Хабре)
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Обзора чего из новинок SwiftUI вы хотите больше?
17.5%
Widget
14
27.5%
AppClips
22
36.25%
Как работать со списками и гридами
29
41.25%
Про перформанс и lifecycle
33
51.25%
Навигация в новых условиях
41
62.5%
Новая архитектура в понимании самих Apple
50
Проголосовали 80 пользователей.
Воздержались 17 пользователей.