美文网首页
SwiftUI -- Property Wrapper

SwiftUI -- Property Wrapper

作者: jancywen | 来源:发表于2021-02-26 15:06 被阅读0次

SwiftUI提供的属性包装器有 @State,@Binding,@ObservedObject,@EnvironmentObject和@Environment 。

一、@State

@State 是属性包装,我们可以用它来描述View的状态。SwiftUI会将其存储在View结构之外的特殊内部存储器中。只有相关的视图可以访问它。@State 属性的值更改后,SwiftUI就会立即重建View以尊重状态更改。

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)
                }
            }
        }
    }
}

二、@Binding

必须绑定值类型

@Binding 为值类型提供类似引用的访问。使用 ** 来传递绑定引用,如果没有 **,它将传递值的副本而不是传递可绑定的引用。

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)
                }
            }
        }
    }
}

FilterView可以读取和写入ProductsView的showFavorited属性的值。一旦FilterView更改showFavorited属性的值,SwiftUI将重新创建ProductsView和FilterView作为其子级。

三、@ObservedObject

该包装器使我们能够观察SwiftUI框架之外的数据模型中的变化。例如业务逻辑,我们可以在多个独立的视图之间共享它,这些视图可以订阅并观察该对象的更改,并且一旦出现更改,SwiftUI就会重建绑定到该对象的所有视图

SwiftUI在@Published属性包装器的帮助下跟踪ObservableObject的更改,并且一旦标记为@Published更改的属性,SwiftUI就会重建绑定到该对象的所有View。在这里,我们使用@ObservedObject 属性包装器将View绑定到ObservableObject类

import Combine

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

    func play() {
        isPlaying = true
    }

    func pause() {
        isPlaying = false
    }
}

struct EpisodesView: View {
    @ObservedObject var player: PodcastPlayer
...
}

ObservableObject可以在多个视图中共享,所以它必须是 引用类型 或者是 类

四、@EnvironmentObject

无需通过View的init方法传递ObservableObject,而是可以将其隐式注入到View层次结构的Environment中。通过这样做,我们为当前Environment的所有子视图访问此ObservableObject创造了机会。

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)              // 通过environmentObject传递ObservableObject
        )
        self.window = window
        window.makeKeyAndVisible()
    }
}

struct EpisodesView: View {
    @EnvironmentObject var player: PodcastPlayer        // 通过使用@EnvironmentObject定义 来轻松访问
... 
}

@EnvironmentObject使用动态成员查找功能在环境中查找ObservableObject的类实例,所以不需要通过View的init方法传递它

五、@Environment

SwiftUI 有一个环境填充了系统范围的设置。我们可以使用@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)
    }
}

通过使用@Environment Property Wrapper标记我们的属性,我们可以访问并订阅系统范围设置的更改。

相关文章

网友评论

      本文标题:SwiftUI -- Property Wrapper

      本文链接:https://www.haomeiwen.com/subject/ntmrfltx.html