首页 > 解决方案 > 如何在 SwiftUI 中观察数组的单个元素

问题描述

假设我有一个 Employee 类,它的图片属性可以被观察到。

internal class Employee: CustomDebugStringConvertible, Identifiable, ObservableObject {
    internal let name: String
    internal let role: Role
    @Published internal var picture: UIImage?
}

使用一个存储员工数组的类。该数组稍后可能会发生变异,因此它是一个 @Published 属性:

internal class EmployeeStorage: ObservableObject {
    @Published internal private(set) var employees: [Employee]
}

现在我有一个使用员工存储的视图列表:

struct EmployeeList: View {
    @ObservedObject var employeeStorage = EmployeeStorage.sharedInstance

    var body: some View {
        // Uses employeeStorage.employee property to draw itself
    }
}

该列表用于内容视图:

struct ContentView: View {
    @ObservedObject var employeeStorage = EmployeeStorage.sharedInstance

    var body: some View {
        // Uses an EmployeeList value
    }
}

假设现在 EmployeeStorage 对象更改了员工数组:这有效地更新了 UI,我可以看到列表已更新为新的员工集合。问题:如果我想在员工的图片属性发生变化时达到同样的效果怎么办?我认为这已经足够了,但在我的例子中(我有一个更复杂的例子),如果员工的图像发生变化,UI 不会更新。怎么做?

标签: swiftswiftui

解决方案


您的代码中有几个问题。

  • Employee模型

    • 你的模型应该是一个结构。
    • 它不需要符合ObservableObject.
    • 你为什么用UIImage!?Image如果您从 Web Api 异步获取数据,只需使用URL,也可能使用 URL。
    • 就像是:

    // Employee Model
    struct Employee: Codable, Identifiable {
        let name: String
        let role: Role
        let imageUrl: String
        let picture: Image
    }
    
  • EmployeeStorage

    • 我怀疑你EmployeeStorage作为单身人士使用的方式是有问题的。Apple 建议您最好使用@EnvironmentObject属性来传递视图及其子视图之间共享的数据。它超级简单,但功能强大!

话虽如此,您可以按如下方式修改代码:

// Employees Store
final class EmployeeStorage: ObservableObject {
    @Published var employees: [Employee]
}

// Content View
struct ContentView: View {
    var employeeStorage = EmployeeStorage()

    var body: some View {
        ...
        EmployeeList()
        .environmentObject(employeeStorage) // here you pass the storage to the list
    }
}

// Employee List
struct EmployeeList: View {
    @EnvironmentObject var employeeStorage: EmployeeStorage

    var body: some View {
        NavigationView {
            List {
                ForEach(employeeStorage.employees) { employee in
                        NavigationLink(
                            destination: EmployeeDetail()
                                .environmentObject(employeeStorage) 
                        ) {
                            EmployeeRow(employee: employee)
                        }
                }.navigationBarTitle(Text("Employees"))
            }
        }
    }
}

有关更多信息,您可以查看内容。它已经完成了你要达到的目标。


推荐阅读