如何在SwiftUI中观察数组中的单个元素。

6

假设我有一个名为“员工”的类,其中的图片属性可以被观察。

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。如何做到这一点?

您的 ContentView 有一个提到 EmployeeList 的注释,但您并没有定义 EmployeeList 类型。什么是 EmployeeListContentView 应该显示 EmployeeStorage 中的所有员工,还是只显示单个 Employee,或者其他内容?如果它只需要显示单个 Employee,为什么需要整个 EmployeeStorage - rob mayoff
1个回答

4
你的代码存在一些问题。
  • Employee Model

    • Your model should be a struct.
    • It does not need to conform to ObservableObject.
    • Why you're using UIImage!? Simply use Image and possibly a URL if you're fetching data from a web Api asynchronously.
    • something like:

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

    • I suspect that the way you're using EmployeeStorage as a singleton is problematic. Apple suggests that you better use an @EnvironmentObject property to pass data shared between views and their subviews. It's super simple, yet robust!
话虽如此,您可以按如下方式修改您的代码:
// 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"))
            }
        }
    }
}

如果您需要更多信息,可以查看这个链接。这个链接里面已经实现了您想要达到的目标。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接