HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-03-10
1 <p>Сегодня мы поговорим о тех изменениях и новшествах, которые нам представляет Apple на WWDC 2020. А именно: про доработанную и даже переработанную версию фреймворка SwiftUI.</p>
1 <p>Сегодня мы поговорим о тех изменениях и новшествах, которые нам представляет Apple на WWDC 2020. А именно: про доработанную и даже переработанную версию фреймворка SwiftUI.</p>
2 <p>Эта технология для декларативной разработки приложений была представлен в прошлом году на WWDC 2019. Если вы с ней еще не работали, то рекомендую заглянуть<a>сюда</a>.</p>
2 <p>Эта технология для декларативной разработки приложений была представлен в прошлом году на WWDC 2019. Если вы с ней еще не работали, то рекомендую заглянуть<a>сюда</a>.</p>
3 <p>Итак. Apple и их инженеры внимательно весь этот год следили за обзорами, статьями, решениями и комментариями от разработчиков-энтузиастов. В конце видео "<a>What's new in SwiftUI</a>" они выражают благодарность всем неравнодушным за помощь.</p>
3 <p>Итак. Apple и их инженеры внимательно весь этот год следили за обзорами, статьями, решениями и комментариями от разработчиков-энтузиастов. В конце видео "<a>What's new in SwiftUI</a>" они выражают благодарность всем неравнодушным за помощь.</p>
4 <p>Теперь SwiftUI позиционируется как полноценный инструмент для разработки под разные платформы (от watchOS до macOS):</p>
4 <p>Теперь SwiftUI позиционируется как полноценный инструмент для разработки под разные платформы (от watchOS до macOS):</p>
5 <p>Причем разработку под разные платформы можно вести в едином проекте. В Xcode 12 появляется шаблон для упрощения создания такого решения:</p>
5 <p>Причем разработку под разные платформы можно вести в едином проекте. В Xcode 12 появляется шаблон для упрощения создания такого решения:</p>
6 <p>Система создаст проект с Shared-блоком и платформенными таргетами, где вы можете добавлять что-то специфичное для конкретной платформы:</p>
6 <p>Система создаст проект с Shared-блоком и платформенными таргетами, где вы можете добавлять что-то специфичное для конкретной платформы:</p>
7 <p>Может показаться, что где-то это вы уже видели в Kotlin Multiplatform. Что ж, видимо, в этом году тренд на явное заимствование у конкурентов.</p>
7 <p>Может показаться, что где-то это вы уже видели в Kotlin Multiplatform. Что ж, видимо, в этом году тренд на явное заимствование у конкурентов.</p>
8 <p>Итак, чтобы обеспечить функционирование на всех поддерживаемых платформах, инженеры Apple проделали огромную работу.</p>
8 <p>Итак, чтобы обеспечить функционирование на всех поддерживаемых платформах, инженеры Apple проделали огромную работу.</p>
9 <p>Расширили поддержку контролов. Теперь практически все контролы UIKit портированы на SwiftUI.</p>
9 <p>Расширили поддержку контролов. Теперь практически все контролы UIKit портированы на SwiftUI.</p>
10 <p>Немаловажно, что в SwiftUI появляется аналог UICollectionView - LazyVGrid/LazyHGrid, использующий GridItem:</p>
10 <p>Немаловажно, что в SwiftUI появляется аналог UICollectionView - LazyVGrid/LazyHGrid, использующий GridItem:</p>
11 <p>Кстати, в процессе работы над новым контролом Apple оптимизировали работу на UITableView/UICollectionView в UIKit.</p>
11 <p>Кстати, в процессе работы над новым контролом Apple оптимизировали работу на UITableView/UICollectionView в UIKit.</p>
12 <p>Появились средства поддержки адаптивности в настройке параметров UI (размеры контролов, шрифт, отступы и т.п). Например, атрибут @ScaledMetric у настраиваемой величины:</p>
12 <p>Появились средства поддержки адаптивности в настройке параметров UI (размеры контролов, шрифт, отступы и т.п). Например, атрибут @ScaledMetric у настраиваемой величины:</p>
13 <p>Также расширили поддержку фреймворков на SwiftUI.</p>
13 <p>Также расширили поддержку фреймворков на SwiftUI.</p>
14 <p>Теперь можно использовать их вместе с ViewState:</p>
14 <p>Теперь можно использовать их вместе с ViewState:</p>
15 Map(coordinateRegion: &lt;#T##Binding&lt;MKCoordinateRegion&gt;#&gt;)<p>Добавили поддержку Document Based Apps, Widgets, App Clips. Последние 2 являются новыми фичами iOS SDK 14. Виджеты - практически аналог того, что было в Android.</p>
15 Map(coordinateRegion: &lt;#T##Binding&lt;MKCoordinateRegion&gt;#&gt;)<p>Добавили поддержку Document Based Apps, Widgets, App Clips. Последние 2 являются новыми фичами iOS SDK 14. Виджеты - практически аналог того, что было в Android.</p>
16 <p>Туториалы и видео работы с ними будут представлены вот-вот на WWDC 2020.</p>
16 <p>Туториалы и видео работы с ними будут представлены вот-вот на WWDC 2020.</p>
17 <p>Появились и более масштабные изменения, связанные с производительностью, архитектурным подходом к созданию приложений и декларативным конструктором:</p>
17 <p>Появились и более масштабные изменения, связанные с производительностью, архитектурным подходом к созданию приложений и декларативным конструктором:</p>
18 <p><strong>1.Оптимизирована работа с памятью. Memory Performance.</strong></p>
18 <p><strong>1.Оптимизирована работа с памятью. Memory Performance.</strong></p>
19 <p>Это глобальное изменение для Swift 5.3 в целом. Переход внутри на структуры позволяет использовать передачу по значению вместо ссылок, тем самым сокращая размер кучи (heap), размер бинарников и времени на компиляцию.</p>
19 <p>Это глобальное изменение для Swift 5.3 в целом. Переход внутри на структуры позволяет использовать передачу по значению вместо ссылок, тем самым сокращая размер кучи (heap), размер бинарников и времени на компиляцию.</p>
20 <p>Кстати, некоторые контролы в самом SwiftUI стали использовать Lazy-подход. Например, те же списки и LazyVGrid/LazyHGrid(аналог UICollectionView). По идее, это должно убрать проблему с инициализацией View сразу. Однако, пока еще ничего не было сказано про NavigationLink…</p>
20 <p>Кстати, некоторые контролы в самом SwiftUI стали использовать Lazy-подход. Например, те же списки и LazyVGrid/LazyHGrid(аналог UICollectionView). По идее, это должно убрать проблему с инициализацией View сразу. Однако, пока еще ничего не было сказано про NavigationLink…</p>
21 <p><strong>2.Использование DSL внутри блоков ViewBuilder.</strong></p>
21 <p><strong>2.Использование DSL внутри блоков ViewBuilder.</strong></p>
22 <p>Ура, теперь мы можем добавить if/else или switch-case в декларативных блоках в своих целях. Например, сделать фабрику Child View внутри родительского View. Или внутри NavigationView.</p>
22 <p>Ура, теперь мы можем добавить if/else или switch-case в декларативных блоках в своих целях. Например, сделать фабрику Child View внутри родительского View. Или внутри NavigationView.</p>
23 <p>Это очень круто.</p>
23 <p>Это очень круто.</p>
24 <p>Также теперь можно проверять условие по @PropertyWrapper внутри блока:</p>
24 <p>Также теперь можно проверять условие по @PropertyWrapper внутри блока:</p>
25 @State private var isVisible = true if isVisible == true { Text("Hello") // Only rendered when isVisible is true. }<p><strong>3.Теперь можно создать приложение 100 % на компонентах SwiftUI.</strong></p>
25 @State private var isVisible = true if isVisible == true { Text("Hello") // Only rendered when isVisible is true. }<p><strong>3.Теперь можно создать приложение 100 % на компонентах SwiftUI.</strong></p>
26 <p>Да-да. Для этого Apple придумали, как обойтись без AppDelegate, SceneDelegate и UIHostingViewController.</p>
26 <p>Да-да. Для этого Apple придумали, как обойтись без AppDelegate, SceneDelegate и UIHostingViewController.</p>
27 <p>С помощью аннотации main и протоколов App, Scene вы сможете этого достичь:</p>
27 <p>С помощью аннотации main и протоколов App, Scene вы сможете этого достичь:</p>
28 @main struct testmultiplatformApp: App { @SceneBuilder var body: some Scene { WindowGroup { MailViewer() } Settings { SettingsView() } } }<p>Кстати, это новая входная точка вашего приложения. Реализация протокола App обязательна. Обратите внимание на тип свойства body-структуры App. В приложении может быть одна или несколько так называемых сцен, каждая из которых реализует протокол Scene. У каждой сцены есть свой root View и свой жизненный цикл. Если вы хотите использовать несколько сцен (как, например, в многооконном приложении), то необходимо поставить у body атрибут SceneBuilder. По сути, это механизм инкапсуляции UISceneDelegate и его логики.</p>
28 @main struct testmultiplatformApp: App { @SceneBuilder var body: some Scene { WindowGroup { MailViewer() } Settings { SettingsView() } } }<p>Кстати, это новая входная точка вашего приложения. Реализация протокола App обязательна. Обратите внимание на тип свойства body-структуры App. В приложении может быть одна или несколько так называемых сцен, каждая из которых реализует протокол Scene. У каждой сцены есть свой root View и свой жизненный цикл. Если вы хотите использовать несколько сцен (как, например, в многооконном приложении), то необходимо поставить у body атрибут SceneBuilder. По сути, это механизм инкапсуляции UISceneDelegate и его логики.</p>
29 <p>WindowGroup используется для создания единого полноразмерного экрана, как и UIWindow/UIWindowScene.</p>
29 <p>WindowGroup используется для создания единого полноразмерного экрана, как и UIWindow/UIWindowScene.</p>
30 <p>Однако, мы помним, что SwiftUI - это надстройка над UIKit. И UIKit остался внутри. Если мы запустим даже вот такое шаблонное приложение, то в иерархии View мы увидим:</p>
30 <p>Однако, мы помним, что SwiftUI - это надстройка над UIKit. И UIKit остался внутри. Если мы запустим даже вот такое шаблонное приложение, то в иерархии View мы увидим:</p>
31 <p>И UIHostingViewController на месте, и UIWindowScene. Но внутри. Да, для инициализации это очень упрощает работу. Но продумали ли они решение, чтобы не пришлось возвращать в приложение UISceneDelegate с явным заданием всей навигационной структуры?</p>
31 <p>И UIHostingViewController на месте, и UIWindowScene. Но внутри. Да, для инициализации это очень упрощает работу. Но продумали ли они решение, чтобы не пришлось возвращать в приложение UISceneDelegate с явным заданием всей навигационной структуры?</p>
32 <p>Отслеживание lifecycle сцены сокращается до метода:</p>
32 <p>Отслеживание lifecycle сцены сокращается до метода:</p>
33 public func onChange&lt;V&gt;(of value: V, perform action: @escaping (V) -&gt; Void) -&gt; some Scene where V : Equatable<p>Вот так предлагают использовать данный метод для отслеживания перехода приложения в фоновое состояние:</p>
33 public func onChange&lt;V&gt;(of value: V, perform action: @escaping (V) -&gt; Void) -&gt; some Scene where V : Equatable<p>Вот так предлагают использовать данный метод для отслеживания перехода приложения в фоновое состояние:</p>
34 /// /// 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. ///<p><strong>4.Изменение предлагаемой архитектуры для SwiftUI.</strong></p>
34 /// /// 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. ///<p><strong>4.Изменение предлагаемой архитектуры для SwiftUI.</strong></p>
35 <p>Видеопрезентации еще не было, но судя по документации на сайте, это уже не MVVM, а MVI или Redux:</p>
35 <p>Видеопрезентации еще не было, но судя по документации на сайте, это уже не MVVM, а MVI или Redux:</p>
36 <p>Да-да, обратите внимание на изменение связей.</p>
36 <p>Да-да, обратите внимание на изменение связей.</p>
37 <p>Что ж, это еще одно подтверждение тренда на заимствование у конкурентов. Пока Google вдохновляются SwiftUI для новой версии JetPack Compose, Apple вдохновляются предложениями Google. Ну а факт заимствования у энтузиастов Apple и не скрывали. Статей, посвященных использованию именно Redux/MVI с SwiftUI, в сети очень много на разных языках еще с прошлого года:<a>ссылка</a>.</p>
37 <p>Что ж, это еще одно подтверждение тренда на заимствование у конкурентов. Пока Google вдохновляются SwiftUI для новой версии JetPack Compose, Apple вдохновляются предложениями Google. Ну а факт заимствования у энтузиастов Apple и не скрывали. Статей, посвященных использованию именно Redux/MVI с SwiftUI, в сети очень много на разных языках еще с прошлого года:<a>ссылка</a>.</p>
38 <p>Как пример.</p>
38 <p>Как пример.</p>
39 <p>И это, конечно, далеко не все. Сессия в самом разгаре, интересное еще впереди. Но в принципе этого уже достаточно, чтобы понять, что меняется многое.</p>
39 <p>И это, конечно, далеко не все. Сессия в самом разгаре, интересное еще впереди. Но в принципе этого уже достаточно, чтобы понять, что меняется многое.</p>
40 <p>Не расстраивайтесь, если у вас были планы на работу с несовершенствами SwiftUi в прошлой реализации. По крайней мере, вы знаете базу и сможете перестроиться на новую версию.</p>
40 <p>Не расстраивайтесь, если у вас были планы на работу с несовершенствами SwiftUi в прошлой реализации. По крайней мере, вы знаете базу и сможете перестроиться на новую версию.</p>
41  
41