自定义数据类型UI绑定
场景:
在收货地址列表页面A中,点击一个地址进详情页面B,然后修改地址保存关闭页面B,收货地址A需要同步UI更新修改的信息。
机制:
1、在SwiftUI中,使用@Binding只能绑定基本数据类型,不能处理自定义数据类型。
2、@StateObject和@ObservedObject的监听,在目前的测试中体现的是向下传递。即页面A创建的模型数组,传递到页面B用@ObservedObject监听,然后在页面A延时修改了数据某个模型中的属性,这时页面A的UI不会更新,页面B的UI会更新。
点击查看问题代码
import SwiftUI
class FruitModelData: ObservableObject {
@Published var fruits: [FruitModel] = [
FruitModel(name: "Apple", count: 5),
FruitModel(name: "Banana", count: 3)
]
}
struct ContentView1: View {
@StateObject var fruitModelData: FruitModelData
var body: some View {
NavigationView {
List {
ForEach(fruitModelData.fruits) { fruit in
NavigationLink(destination: FruitDetail(fruit: fruit)) {
HStack {
Text(fruit.name)
Text("\(fruit.count)")
}
}
}
}
}
}
}
// FruitDetail.swift
struct FruitDetail: View {
@ObservedObject var fruit: FruitModel
var body: some View {
VStack {
Text("Name: \(fruit.name)")
Text("Count: \(fruit.count)")
Button("Increment Count") {
fruit.count += 1
}
}
}
}
struct DSTest_Previews: PreviewProvider {
static var previews: some View {
ContentView1(fruitModelData: FruitModelData())
}
}
解决方案:
@Binding
通过上面的两个现象可以得出,要在页面B修改属性的时候,同时向上反馈更新页面A的UI,那就只能用到@Binding,所以做法是把模型拆分成基本数据类型
点击查看@Binding代码
import SwiftUI
class FruitModelData: ObservableObject {
@Published var fruits: [FruitModel] = [
FruitModel(name: "Apple", count: 5),
FruitModel(name: "Banana", count: 3)
]
}
struct ContentView1: View {
@StateObject var fruitModelData: FruitModelData
var body: some View {
NavigationView {
List {
ForEach(fruitModelData.fruits.indices, id: \.self) { i in
let model = fruitModelData.fruits[i]
NavigationLink(destination: FruitDetail(fruit: model, count: $fruitModelData.fruits[i].count)) {
HStack {
Text(model.name)
Text("\(model.count)")
}
}
}
}
}
}
}
// FruitDetail.swift
struct FruitDetail: View {
@ObservedObject var fruit: FruitModel
@Binding var count: Int
var body: some View {
VStack {
Text("Name: \(fruit.name)")
Text("Count: \(fruit.count)")
Button("Increment Count") {
count += 1
}
}
}
}
struct DSTest_Previews: PreviewProvider {
static var previews: some View {
ContentView1(fruitModelData: FruitModelData())
}
}
combine
既然我们修改单个模型中的属性无法触发更新,那我们就直接通知更新整个数组,这样使用到的UI都会刷新
点击查看objectWillChange代码
import SwiftUI
class FruitModelData: ObservableObject {
@Published var fruits: [FruitModel] = [
FruitModel(name: "Apple", count: 5),
FruitModel(name: "Banana", count: 3)
]
}
struct ContentView1: View {
@StateObject var fruitModelData: FruitModelData
var body: some View {
NavigationView {
List {
ForEach(fruitModelData.fruits) { fruit in
NavigationLink(destination: FruitDetail(fruit: fruit, fruitModelData: fruitModelData)) {
HStack {
Text(fruit.name)
Text("\(fruit.count)")
}
}
}
}
}
}
}
// FruitDetail.swift
struct FruitDetail: View {
@ObservedObject var fruit: FruitModel
var fruitModelData: FruitModelData //这里把整个数组的对象传递过来
var body: some View {
VStack {
Text("Name: \(fruit.name)")
Text("Count: \(fruit.count)")
Button("Increment Count") {
fruit.count += 1
//既然修改其中一个模型触发不了,那我就通知你整个模型,我已经更新了数据,但是需要集成ObservableObject
fruitModelData.objectWillChange.send()
}
}
}
}
struct DSTest_Previews: PreviewProvider {
static var previews: some View {
ContentView1(fruitModelData: FruitModelData())
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库