WWDC 2020: изменения в фреймворке SwiftUI | OTUS
Запланируйте обучение с выгодой в Otus!
-15% на все курсы до 30.11 Забрать скидку! →
Выбрать курс

WWDC 2020: изменения в фреймворке SwiftUI

Сегодня мы поговорим о тех изменениях и новшествах, которые нам представляет Apple на WWDC 2020. А именно: про доработанную и даже переработанную версию фреймворка SwiftUI.

Эта технология для декларативной разработки приложений была представлен в прошлом году на WWDC 2019. Если вы с ней еще не работали, то рекомендую заглянуть сюда.

Итак. Apple и их инженеры внимательно весь этот год следили за обзорами, статьями, решениями и комментариями от разработчиков-энтузиастов. В конце видео «What's new in SwiftUI» они выражают благодарность всем неравнодушным за помощь.

Теперь SwiftUI позиционируется как полноценный инструмент для разработки под разные платформы (от watchOS до macOS):

1__2-20219-00d177.jpg

Причем разработку под разные платформы можно вести в едином проекте. В Xcode 12 появляется шаблон для упрощения создания такого решения:

wlu2g8doeqfmm7i2airnzx0wih0_1-20219-2faee8.png

Система создаст проект с Shared-блоком и платформенными таргетами, где вы можете добавлять что-то специфичное для конкретной платформы:

dguiaodpdzfhm4_cve_4dvypmb0_1-20219-3d23ea.png

Может показаться, что где-то это вы уже видели в Kotlin Multiplatform. Что ж, видимо, в этом году тренд на явное заимствование у конкурентов.

Итак, чтобы обеспечить функционирование на всех поддерживаемых платформах, инженеры Apple проделали огромную работу.

Расширили поддержку контролов. Теперь практически все контролы UIKit портированы на SwiftUI.

2-20219-c31c40.png

Немаловажно, что в SwiftUI появляется аналог UICollectionView — LazyVGrid/LazyHGrid, использующий GridItem:

2-20219-a0d042.png

Кстати, в процессе работы над новым контролом Apple оптимизировали работу на UITableView/UICollectionView в UIKit.

Появились средства поддержки адаптивности в настройке параметров UI (размеры контролов, шрифт, отступы и т.п). Например, атрибут @ScaledMetric у настраиваемой величины:

2-20219-71625b.png

Также расширили поддержку фреймворков на SwiftUI.

2-20219-d6d53d.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), размер бинарников и времени на компиляцию.

2-20219-92ce3b.png

Кстати, некоторые контролы в самом SwiftUI стали использовать Lazy-подход. Например, те же списки и LazyVGrid/LazyHGrid(аналог UICollectionView). По идее, это должно убрать проблему с инициализацией View сразу. Однако, пока еще ничего не было сказано про NavigationLink…

2.Использование DSL внутри блоков ViewBuilder.

Ура, теперь мы можем добавить if/else или switch-case в декларативных блоках в своих целях. Например, сделать фабрику Child View внутри родительского View. Или внутри NavigationView.

2-20219-99f224.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()
        }
    }
}

Кстати, это новая входная точка вашего приложения. Реализация протокола App обязательна. Обратите внимание на тип свойства body-структуры App. В приложении может быть одна или несколько так называемых сцен, каждая из которых реализует протокол Scene. У каждой сцены есть свой root View и свой жизненный цикл. Если вы хотите использовать несколько сцен (как, например, в многооконном приложении), то необходимо поставить у body атрибут SceneBuilder. По сути, это механизм инкапсуляции UISceneDelegate и его логики.

WindowGroup используется для создания единого полноразмерного экрана, как и UIWindow/UIWindowScene.

Однако, мы помним, что SwiftUI — это надстройка над UIKit. И UIKit остался внутри. Если мы запустим даже вот такое шаблонное приложение, то в иерархии View мы увидим:

2-20219-0dc9e4.jpg

И 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:

k6jxpxica4d1hvfu2vxacggl3tm_1-20219-093378.png

Да-да, обратите внимание на изменение связей.

Что ж, это еще одно подтверждение тренда на заимствование у конкурентов. Пока Google вдохновляются SwiftUI для новой версии JetPack Compose, Apple вдохновляются предложениями Google. Ну а факт заимствования у энтузиастов Apple и не скрывали. Статей, посвященных использованию именно Redux/MVI с SwiftUI, в сети очень много на разных языках еще с прошлого года: ссылка.

Как пример.

И это, конечно, далеко не все. Сессия в самом разгаре, интересное еще впереди. Но в принципе этого уже достаточно, чтобы понять, что меняется многое.

Не расстраивайтесь, если у вас были планы на работу с несовершенствами SwiftUi в прошлой реализации. По крайней мере, вы знаете базу и сможете перестроиться на новую версию.

Не пропустите новые полезные статьи!

Спасибо за подписку!

Мы отправили вам письмо для подтверждения вашего email.
С уважением, OTUS!

Автор
0 комментариев
Для комментирования необходимо авторизоваться
Популярное
Сегодня тут пусто
Черная пятница в Otus! ⚡️
Скидка 15% на все курсы до 27.11 →