Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What are the knowledge points of SwiftUI?

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article mainly explains "what are the knowledge points of SwiftUI". The content of the explanation is simple and clear, and it is easy to learn and understand. Please follow the editor's train of thought to study and learn "what are the knowledge points of SwiftUI".

I. background

At the 2019 WWDC Global developer Conference, Apple released a declarative framework based on Swift-SwiftUI, which can be used for application development of Apple products such as watchOS, tvOS, macOS and other Apple products, unifying the UI framework of the Apple platform.

As the official website says, Better apps. Less code: build better applications with less code. Currently, to experience SwiftUI, you need the following preparations: Xcode 11 beta and macOS Mojave or Higher, and macOS 10.15 beta if you want to experience real-time preview and full Xcode 11 functionality.

This article mainly describes the characteristics of SwiftUI from the following three aspects:

Understanding the underlying implementation of the new syntax of Swift 5.1 from the code level

Explain the dark magic of SwiftUI from the aspect of data flow

This paper expounds the advantages of SwiftUI component from the aspect of layout principle.

II. Characteristics of SwiftUI

This section explains the three new grammatical features of Opaque Result Type, PropertyDelegate and FunctionBuilder, combined with some pseudocode and data flow analysis, to understand their role in SwiftUI from simple to deep.

2.1 Opaque Result Type

Create a new project for SwiftUI and the following code appears: a Text is displayed in body.

Struct ContentView: View {var body: some View {Text ("Hello World")}}

For the emergence of some View, you may feel very sudden. In general, the type returned in the closure should be the type used to specify the body, as shown in the following code, if there is only one Text in the closure, then the type of body should be Text.

Struct ContentView: View {var body: Text {Text ("Hello World")}}

However, in many cases, it is impossible to determine the specific types of closures in the UI layout, which may be Text, Button, List, and so on. In order to solve this problem, Opaque Result Type is generated.

In fact, View is a core protocol of SwiftUI and represents the description of the elements in the closure. As shown in the following code, it is decorated by an associatedtype, and a protocol with this modification cannot be used as a type, but only as a type constraint.

Through the modification of Some View, it assures the compiler that each closure must return a certain type that complies with the View protocol, regardless of which type it is. This design provides a flexible development model for developers, erases specific types, does not need to modify the public API to determine the return type of each closure, and reduces the difficulty of code writing.

Public protocol View: _ View {associatedtype Body: View var body: Self.Body {get}} 2.2 PropertyDelegate

The complex UI structure has always been the pain point of the front-end layout, every time the user interaction or data changes, the UI needs to be updated in time, otherwise it will cause some display problems. However, in SwiftUI, any state, content, and layout declared in the view will automatically update the view as soon as the source changes, so the layout is only needed once. Add the @ State keyword in front of the attribute to achieve the effect of dynamic UI update each time the data is changed.

@ propertyDelegate public struct State: DynamicViewProperty, BindingConvertible

In the above code, a @ State keyword inherits DynamicViewProperty and BindingConvertible,BindingConvertible as bindings to attribute values, and DynamicViewProperty binds View and attributes dynamically.

In other words, when declaring a property, SwiftUI will bind the state of the current property to the corresponding view. When the state of the property changes, the current view will destroy the previous state and update it in time. Let's analyze this process in detail. In general, the initialization of a String attribute is implemented as follows:

Public struct MyValue {var myValueStorage: String? = nil public var myValue: String {get {myValue = myValueStorage return myValueStorage} set {myValueStorage = newValue}

If there are a lot of such attributes in the code, and some of them are specifically handled, the above writing will undoubtedly create a lot of redundancy. The emergence of the property agent (propertyDelegate) solves this problem. The property agent is a generic type through which different types of properties can be specifically handled:

@ propertyDelegate public struct LateInitialized {private var storage: Value? Public init () {storage = nil} public var value: Value {get {guard let value = storage createDependency (view, value) / / establish views and data dependencies return value} set {if (storage! = newValue) {storage = newValue notify (to: swiftui) / / notify SwiftUI of data changes}

The function of the above code is shown in the figure above. Through the modification of @ propertyDelegate, you can solve different types of value for specific processing; the above wrapper method can establish the relationship between view and data, and will judge that when the attribute value changes, notify SwiftUI to refresh the view, and the compiler can generate the following code for String type myValue. The decorated code looks very concise.

Public struct MyValue {var $myValue: LateInitialized = LateInitialized () public var myValue: String {get {$myValue} set {$myValue.value = newValue}

Next, let's look at the source code of @ State:

@ available (iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *) @ propertyDelegate public struct State: DynamicViewProperty, BindingConvertible {/ Initialize with the provided initial value. Public init (initialValue value: Value) / The current state value. Public var value: Value {get nonmutating set} / Returns a binding referencing the state value. Public var binding: Binding {get} / Produces the binding referencing this state value public var delegateValue: Binding {get} / Produces the binding referencing this state value / TODO: old name for storageValue, to be removed public var storageValue: Binding {get}} @ available (iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *) extension State where Value: ExpressibleByNilLiteral {/ / Initialize with a nil initial value. @ inlinable public init ()}

Swift 5.1new feature Property Wrappers (a kind of attribute decoration syntax sugar) to modify State, the internal implementation is probably in the properties Get, Set, part of the reusable code packaging, the above said that "the attribute proxy is a generic type" can efficiently implement this part of the function.

@ State internally establishes the relationship between the data source and the view during Get, and returns the current data reference so that the view can be obtained. In the Set method, it listens for changes in the data, informs SwiftUI to retrieve the view body, reconstructs the UI through the Function Builders method, and draws the interface. In the drawing process, it will automatically compare whether the various properties of the view have changed. If there is a change, the corresponding view will be updated. Avoid global drawing and waste of resources.

Through this programming model, SwiftUI helps developers establish connections between various views and data, and deal with the relationship between the two. Developers only need to pay attention to business logic. The official data structure diagram is as follows:

In the process of user interaction, a user's action is generated. As you can see from the figure above, the flow of data in SwiftUI is as follows:

This behavior triggers data changes and is wrapped by @ State data sources

@ State detects data changes and triggers view redrawing

According to the logic mentioned above, the SwiftUI determines whether the corresponding view needs to update the UI, and finally presents it to the user again, waiting for the interaction.

This is the interactive flow of SwiftUI, where the data flow between each node is one-way and independent, and this pattern is similar to the data schema of Flux and Redux architectures, no matter how complex the logic of the application becomes.

Internally, it is composed of numerous such one-way data streams, each of which follows the corresponding specifications, so that when troubleshooting problems, developers no longer need to find all the interfaces related to the data for troubleshooting. You just need to find the corresponding logical data flow and analyze whether the data is working properly in the process.

SwiftUI provides different keywords in different scenarios, and its implementation principle is shown above:

@ State-the view is dependent on the data, and the data changes should be synchronized to the view

@ Binding-the parent-child view is directly dependent on data, and data changes should be synchronized to the parent-child view

@ BindableObject-external data structures are dependent on SwiftUI establishment data

@ EnvironmentObject-Quick access to global data sources across components

The implementation of the above features is based on Swift's Combine framework, which is briefly described below. The framework has two very important concepts, observer mode and responsive programming.

The observer pattern describes an one-to-many relationship: one object will automatically notify other objects when it changes, and other objects will react accordingly. These two types of objects are called observed objects and observers, respectively. One observation target can correspond to multiple observers, and observers can subscribe to what they are interested in. This is the source of the keyword @ State in this paper, taking the attribute as the observation target, and the observer is multiple View with this attribute.

The core of responsive programming is oriented to asynchronous data streams and changes. Responsive programming converts all events into asynchronous data streams, which makes it more convenient to combine and transform these data streams, and finally only needs to monitor the changes of data streams and deal with them, so it is very simple to deal with user interaction and response in SwiftUI.

2.3 FunctionBuilder

Before you know FunctionBuilder, you must first understand ViewBuilder, which is decorated with @ _ functionBuilder, which the compiler will use. And there are certain requirements for the methods it contains, which are hidden in the last closure parameter of each container type. The so-called "requirements" are described in detail below.

In the composite view, a large number of UI components are handled in the closure. FunctionBuilder establishes the style through the closure and passes the UI description in the closure to a special constructor, providing a development pattern similar to DSL. Implement a simple View as follows:

Struct RowCell: View {let image: UIImage let title: String let tip: String var body: some View {HStack {Image (uiImage: image) Text (title) Text (tip)}

Take a look at the initialization code of HStack, as shown below: its final content is decorated with ViewBuilder, that is, the closure expression is specially handled by functionBuilder to construct the view.

Init (alignment: VerticalAlignment = .center, spacing: Length? = nil, @ ViewBuilder content: ()-> Content)

Without the new feature of FunctionBuilder, the developer must manage the container view, taking HStack as an example (as shown in the following code). If there are a large number of expressions, it will undoubtedly give developers a headache, and the code will be messy and the structure is not clear enough.

Struct RowCell: View {let image: UIImage let title: String let tip: String var body: some View {var builder = HStackBuilder () builder.add (Image (uiImage: image) builder.add (Text (title)) builder.add (Text (tip)) return builder.build ()}}

Content decorated with @ _ functionBuilder implements a constructor that functions as shown in the above code. The builder declares several buildBlock methods for constructing views that satisfy a wide variety of closure expressions. Here are several ViewBuilder methods for SwiftUI:

Building Blocksstatic func buildBlock ()-> EmptyView//Builds an empty view from a block containing no statements.static func buildBlock (Content)-> Content//Passes a single view written as a child view through unmodified.static func buildBlock (C0, C1)-> TupleViewstatic func buildBlock (C0, C1, C2)-> TupleViewstatic func buildBlock (C0, C1, C2, C3)-> TupleView...

When the content,content modified by ViewBuilder is called, the view is built according to the above appropriate buildBlock, build the Text or other components in the closure into a TupleView, and return.

However, @ _ functionBuilder also has some limitations. A maximum of ten parameters can be passed in the buildBlock of ViewBuilder, that is, there can be no more than ten View; in the layout. If there are more than ten View, you can consider using TupleView to merge View in a multiple way.

As one of the new features of SwiftUI, FunctionBuilder prefers the current popular programming approach, where developers can use DSL-based architectures such as SwiftUI without having to consider the specific implementation details, because the builder implements a DSL itself.

III. Components

Through the analysis of DSL view, this section analyzes the characteristics of SwfitUI in layout and the advantages of using this feature in the process of componentization.

At present, component-based programming is the mainstream way of development, SwfitUI brings a new function-can build reusable components, using the idea of declarative programming. Combine a single, simple response view into a tedious and complex view, and the component can be used on any platform on Apple, achieving a cross-platform effect (Apple devices only). According to the purpose, it can be divided into basic components, layout components and functional components.

See example link for more details on the components.

Let's take a Button as an example:

Struct ContentView: View {var body: some View {Button (action: {/ / did tap}, label: {Text ("Click me")}) .foreground Color (Color.white) .cornerRadius (5) .padding (20) .background (Color.blue)}}

It contains a Button, and its parent view is a ContenView. In fact, ContenView will also be contained by a RootView. RootView is created by SwiftUI on Window. Through a few simple lines of code, set the button click event, style and copywriting.

The view DSL structure is shown in the following figure. SwiftUI will directly read the internal description information of the DSL and collect it, then convert it into a basic graphics unit, and finally render it to the underlying Metal or OpenGL.

Through this structure, it is found that it is very different from the layout structure of UIKit. Some properties of buttons, such as background, padding, cornerRadius, etc., should not appear in the main structure of the view, but should appear in the structure of the Button view.

Because, in SwiftUI, the settings of these attributes will be carried by a View internally, and then the layout will follow the layout flow of the above example, layer by layer of View calculation. The advantage of this is that it is easier for the underlying layer to achieve monomorphic call when designing rendering functions, eliminating useless branch judgment and improving efficiency.

At the same time, the frame setting is also supported in SwiftUI, but it does not act on the current element as it does in UIKit, and a virtual View is formed internally to hold the frame setting. The frame calculation in the layout process finally shows the desired results.

In short, setting properties for a View in SwiftUI is no longer a constraint for the current element, but a series of containers that contain the current element in preparation for subsequent layout calculations.

SwiftUI interface is no longer like UIKit, using ViewController to carry all kinds of UIVew controls, but everything is View, so View can be divided into various detailed components, and then assembled into the final interface, this kind of view assembly way improves the flexibility and reusability of interface development. Therefore, view componentization is a big bright spot of SwiftUI.

IV. See it live in Xcode

SwiftUI's Preview is a major breakthrough for Apple, similar to RN's and Flutter's Hot Reloading. Apple chose to render directly on macOS, but macOS 10.15 with SwiftUI.framework is required to see the Xcode Previews interface.

Xcode will do a static analysis of the code (thanks to the SwiftSyntax framework) to find all types that comply with the PreviewProvider protocol for preview rendering. Real-time preview and static preview are provided in Xcode 11, real-time preview: changes to the code can be presented in the preview window of Xcode in real time; in addition, Xcdoe also provides a quick function, through command+ mouse click components, you can quickly and easily add components and set component properties.

Thank you for your reading, these are the contents of "what are the knowledge points of SwiftUI". After the study of this article, I believe you have a deeper understanding of what are the knowledge points of SwiftUI, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report