SwiftUI 属性包装器系列 --- @Observable @Bindable

@Observable

@Observable在 WWDC23 上发布,旨在简化观察相关代码并提高应用程序的性能。

性能提升来自于这样一个事实:SwiftUI 开始跟踪 SwiftUI 视图主体中使用了哪些属性,只有当跟踪的属性发生更改时才会触发视图渲染。如果同一模型对象中的任何其他属性发生变化,则不会发生新的重新渲染 - 非常好。

利用@Observable@Bindable来替代以前的ObservableObject、@Published@StateObject的写法,主要区别在于我们可以放弃使用 @Published 属性包装器,而不是遵守 ObservableObject 协议,而是在视图模型定义前面添加 @Observable 。

符合 ObservableObject 写法:

swift 复制代码
class ContentViewModel: ObservableObject {
    @Published var username: String = ""
}

struct ContentView: View {
    @StateObject private var viewModel = ContentViewModel()
    var body: some View {
        VStack {
            TextField("Username", text: $viewModel.username)
        }
    }
}

@Observable 写法:

swift 复制代码
@Observable 
class Content2ViewModel {
    var username: String = ""
}

struct ContentView2: View {
    @Bindable private var viewModel = Content2ViewModel()
    var body: some View {
        VStack {
            TextField("Username", text: $viewModel.username)
        }
    }
}

@Bindable

@Bindable包装器是为了解决这种情况而创建的,它允许您创建到对象属性的绑定,用于创建与带@Observable注释的模型上的属性的绑定。如果不使用@Bindable就不能与@Observable的模型的进行绑定。

swift 复制代码
@Observable
class SearchModel {
  var query: String = ""
  var results: [SearchResult] = []
  // ...
}

struct SearchView {
  let searchModel: SearchModel
  var body: some View {
    // Cannot find '$searchModel' in scope
    TextField("Search query", text: $searchModel.query)
  }
}

我们无法绑定到一个普通的 SearchModel的属性,我们需要某种机制来实现这一点,我们可以使用以下的方式:

  1. 是使用上一篇文章提到的Binding,创建Binding实例并传递一个getset闭包。

  2. @Bindable属性包装器:

swift 复制代码
struct SearchView {
  @Bindable var searchModel: SearchModel
  var body: some View {
    // This works
    TextField("Search query", text: $searchModel.query)
  }
}

@Bindable可以从属性包装器获取投影值,并且投影值提供我们的绑定。换句话说,我们现在可以对模型的query属性绑定。

less 复制代码
struct SearchView {
  @Environment(.searchModel) var searchModel

  var body: some View {
    @Bindable var bindableSearchModel = searchModel
    // This works
    TextField("Search query", text: $bindableSearchModel.query)
  }
}

使用此技术,您可以从环境中提取搜索模型作为不可绑定的属性。为了使其可绑定,您可以在主体内部创建一个标记为 的影子属性@Bindable

@Bindable注意事项:

  • 您正在包装一个带有注释的类@Observed
  • 您需要提供另一个视图来绑定到模型对象上的属性

请注意: 您永远不会在@Binding@Bindable之间进行选择。@Binding属性包装器表明视图上的某些状态由父视图拥有,并且您对基础数据具有读写访问权限。@Bindable表示用于创建与符合Observable协议的数据模型对象的可变属性的绑定。

相关推荐
2501_915909062 天前
SwiftUI 和 UIKit 怎么选?两代 UI 框架的适用范围
vscode·ios·objective-c·个人开发·swift·敏捷流程
2501_915918412 天前
在Windows10上使用VSCode和Code Runner搭建Swift开发环境详细步骤
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
用户468104557243 天前
Swift 异步与并发
swift
安当加密03013 天前
PCI DSS 4.0与SWIFT CSP双合规:银行收单与跨境支付HSM部署实战
swift·hsm·密钥管理·pci dss·双合规
麒麟马4 天前
Swift 扩展归纳---Array (一)
ios·swift
2501_915106324 天前
Swift 4开发环境设置教程:xCode安装与Playground入门
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
东坡肘子5 天前
当 Mac mini 的价格不再 mini -- 肘子的 Swift 周报 #152
人工智能·swiftui·swift
2501_915106328 天前
第一次开发 iPhone App,可能碰到的问题,解决办法
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
末代iOS程序员华仔9 天前
iOS 5.6 条例解决方法
flutter·ios·swift
末代iOS程序员华仔9 天前
Guideline 5.6 - Developer Code of Conduct
flutter·ios·swift