The original address: mecid. Making. IO / 2019/06/12 /…

@State

We can correlate the State of the View by using the @state decorator. SwiftUI will store attributes that use the @State modifier in a special memory area that is isolated from the View struct. When the @State decorated property changes, SwiftUI recreates the view based on the new property value

struct ProductsView: View {
    let products: [Product]

    @State private var showFavorited: Bool = false

    var body: some View {
        List {
            Button(
                action: { self.showFavorited.toggle() },
                label: { Text("Change filter")})ForEach(products) { product in
                if !self.showFavorited || product.isFavorited {
                    Text(product.title)
                }
            }
        }
    }
}
Copy the code

In this example we create a list. Click showFavorited and the value is reversed. SwiftUI updates the value with the latest value

The demo doesn’t work in the latest Xcode 11 Beta 6 because the syntax of the Button component has been changed

@Binding

Sometimes we pass a view property to a child node, but we cannot pass it directly to the child node, because in Swift the value is passed as a value type, that is, a copied value is passed to the child node. But with the @Binding modifier, the property becomes a reference type and the pass becomes a reference pass, so that the state of the parent and child views can be correlated.

struct FilterView: View {@Binding var showFavorited: Bool

    var body: some View {
        Toggle(isOn: $showFavorited) {
            Text("Change filter")}}}struct ProductsView: View {
    let products: [Product]

    @State private var showFavorited: Bool = false

    var body: some View {
        List {
            FilterView(showFavorited: $showFavorited)

            ForEach(products) { product in
                if !self.showFavorited || product.isFavorited {
                    Text(product.title)
                }
            }
        }
    }
}
Copy the code

In FilterView, we use @binding to modify the showFavorited property and $to pass a reference to the showFavorited property. SwiftUI will update the ProductsView and FilterView views

In the FilterView, the Toggle component is also createdShowFavorited, just Text

@ObservedObject

@observedobject is very similar to @State in that its name is used to decorate an object that can be used by multiple independent views. If you use @observedobject to modify an object, that object must implement the ObservableObject protocol, and then use @Published to modify the property in the object, indicating that the property needs to be listened on by SwiftUI

final class PodcastPlayer: ObservableObject {@Published private(set) var isPlaying: Bool = false

    func play(a) {
        isPlaying = true
    }

    func pause(a) {
        isPlaying = false}}Copy the code

We define a PodcastPlayer class that can be used by different views. SwiftUI tracks @published property changes in the @ObservableObject modified object of the View. Once the changes are made, SwiftUI will update the associated UI

struct EpisodesView: View {@ObservedObject var player: PodcastPlayer
    let episodes: [Episode]

    var body: some View {
        List {
            Button(
                action: {
                    if self.player.isPlaying {
                        self.player.pause()
                    } else {
                        self.player.play()
                    }
            }, label: {
                    Text(player.isPlaying ? "Pause": "Play")})ForEach(episodes) { episode in
                Text(episode.title)
            }
        }
    }
}
Copy the code

The demo doesn’t work in the latest Xcode 11 Beta 6 because the syntax of the Button component has been changed

@EnvironmentObject

As the name suggests, this decorator is specific to the global environment. With this, we can avoid creating an ObservableObject in the initial View and instead get an ObservableObject from the environment

SceneDelegate. Swift file

class SceneDelegate: UIResponder.UIWindowSceneDelegate {

    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        let window = UIWindow(frame: UIScreen.main.bounds)
        let episodes = [
            Episode(id: 1, title: "First episode"),
            Episode(id: 2, title: "Second episode")]let player = PodcastPlayer()
        window.rootViewController = UIHostingController(
            rootView: EpisodesView(episodes: episodes)
                .environmentObject(player)
        )
        self.window = window
        window.makeKeyAndVisible()
    }
}
Copy the code

EpisodesView. Swift file

struct EpisodesView: View {@EnvironmentObject var player: PodcastPlayer
    let episodes: [Episode]

    var body: some View {
        List {
            Button(
                action: {
                    if self.player.isPlaying {
                        self.player.pause()
                    } else {
                        self.player.play()
                    }
            }, label: {
                    Text(player.isPlaying ? "Pause": "Play")})ForEach(episodes) { episode in
                Text(episode.title)
            }
        }
    }
}
Copy the code

You can see that we get the PodcastPlayer ObservableObject via the @environmentobject decorator, but in the entry we need to pass.environmentobject (Player). The way @environmentobject works is to find PodcastPlayer instances in Environment.

@Environment

SwiftUI does have a lot of system level Settings, so we need to get them via @environment

struct CalendarView: View {@Environment(\.calendar) var calendar: Calendar
    @Environment(\.locale) var locale: Locale
    @Environment(\.colorScheme) var colorScheme: ColorScheme

    var body: some View {
        return Text(locale.identifier)
    }
}
Copy the code

Using the @environment attribute, we need to listen for system-level changes. In this example, once the Calendar, Locale, and ColorScheme changes, our CalendarView will refresh

thank you