I welcome you, residents of Habr and everyone interested in developing for iOS. Connected Anna Zharkova, Senior iOS/Android Developer, Usetech
Today we’ll talk about the changes and innovations that Apple presents to us at WWDC 2020. Namely, about a revised and even revised version of the SwiftUI framework.

This technology for declarative application development was introduced last year at WWDC 2019. If you have not worked with it, I recommend that you look here

So. Apple and their engineers have been closely following this year's reviews, articles, solutions, and comments from enthusiastic developers. At the end of the video "What's new in SwiftUI" they thank everyone who cares for their help.

Now SwiftUI is positioned as a complete development tool for different platforms (from watchOS to macOS):

ITKarma picture

Moreover, development for different platforms can be carried out in a single project. A template appears in Xcode 12 to simplify the creation of such a solution:

ITKarma picture

The system will create a project with a Shared block and platform targets, where you can add something specific to a particular platform:

ITKarma picture

It might seem that somewhere you already saw this in Kotlin Multiplatform . Well, apparently, this year the trend for explicit borrowing from competitors.

So, to ensure operation on all supported platforms, Apple engineers have done a great job.

We expanded the support of controls. Now almost all UIKit controls are ported to SwiftUI

ITKarma picture

It is important that in SwiftUI an analogue of UICollectionView - LazyVGrid/LazyHGrid using GridItem appears:

ITKarma picture

By the way, in the process of working on the new control, Apple optimized work on the UITableView/UICollectionView in UIKit.

There are tools to support adaptability in configuring UI parameters (control sizes, font, indents, etc.). For example, the @ScaledMetric attribute of a custom variable:

ITKarma picture

Also expanded support for SwiftUI frameworks.

ITKarma picture

Now you can use them with ViewState:

Map(coordinateRegion: <#T##Binding<MKCoordinateRegion>#>) 

Added support for Document Based Apps, Widgets, App Clips. The last 2 are new features of iOS SDK 14. Widgets are almost an analogue of what was in Android.

Tutorials and videos of working with them will be presented right now at WWDC 2020.

There are also more large-scale changes related to performance, architectural approach to creating applications and declarative constructor:

1. Optimized memory handling. Memory performance.

This is a global change for Swift 5.3 as a whole. Going inside structures allows you to use passing by value instead of references, thereby reducing the size of the heap (heap), the size of binaries and compilation time.

ITKarma picture

By the way, some controls in SwiftUI itself began to use the Lazy approach. For example, the same lists and LazyVGrid/LazyHGrid (similar to UICollectionView). In theory, this should remove the problem of initializing the View immediately. However, so far nothing has been said about NavigationLink... .

2. Using DSL inside ViewBuilder blocks.

Hooray, now we can add if/else or switch-case in declarative blocks for our purposes. For example, make the Child View factory inside the parent View. Or inside NavigationView.

ITKarma picture

It is very cool.

Also now you can check the condition by @PropertyWrapper inside the block:

@State private var isVisible=true if isVisible == true { Text("Hello")//Only rendered when isVisible is true. } 

3. Now you can create a 100% application on SwiftUI components.

Yes Yes. To do this, Apple came up with how to do without AppDelegate, SceneDelegate and UIHostingViewController.

Using the main annotation and the Scene App protocols, you can achieve this:

@main struct testmultiplatformApp: App { @SceneBuilder var body: some Scene { WindowGroup { MailViewer() } Settings { SettingsView() } } } 

main signals that this is the new entry point of your application. Implementation of the App protocol is required. Note the type of body property of the App structure. An application can have one or more so-called scenes, each of which implements the Scene protocol. Each scene has its own root View and its life cycle. If you want to use several scenes (as, for example, in a multi-window application), then you need to set the SceneBuilder attribute on the body. This is essentially the encapsulation mechanism of UISceneDelegate and its logic.

WindowGroup is used to create a single full-size screen, like UIWindow/UIWindowScene.

However, we remember that SwiftUI is an add-on for UIKit. And UIKit stayed inside. If we even launch such a template application, then in the View hierarchy we will see:

ITKarma picture

Both the UIHostingViewController in place and the UIWindowScene. But inside. Yes, for initialization, this greatly simplifies the work. But did they think of a solution so that they would not have to return UISceneDelegate to the application with an explicit job of the entire navigation structure.

Tracking the lifecycle scene is reduced to a method:

public func onChange<V>(of value: V, perform action: @escaping (V) -> Void) -> some Scene where V : Equatable 

This is how they suggest using this method to track the transition of the application to the background state:

//////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. Change the proposed architecture for SwiftUI.

There was no video presentation yet, but judging by the documentation on the site, this is not MVVM, but MVI or Redux:

ITKarma picture>
Yes, pay attention to the change in relationships.

Well, this is another confirmation of the trend for borrowing from competitors. While Google is inspired by SwiftUI for the new version of JetPack Compose, Apple is inspired by Google's offerings. Well, the fact of borrowing from Apple enthusiasts was not hidden. There are a lot of articles on the use of Redux/MVI with SwiftUI on the network in different languages ​​since last year: link .

As an example.

And this, of course, is far from all. The session is in full swing, interesting is yet to come. But in principle, this is already enough to understand that a lot is changing.

Do not be discouraged if you had plans to work with SwiftUi imperfections in the previous implementation. At least you know the base and can upgrade to a new version.

In general, join WWDC 2020. And wait for new articles on Habré)