Как наблюдать за отдельными элементами массива в SwiftUI - PullRequest
3 голосов
/ 11 октября 2019

Допустим, у меня есть класс 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 изменяет мутирующий массив сотрудников: это эффективно обновляет пользовательский интерфейс, и я вижу, что список обновляется с новой коллекцией сотрудников. Проблема: что если я захочу добиться того же эффекта при изменении свойства изображения сотрудника? Я подумал, что этого достаточно, но в моем случае (у меня есть более сложный пример) пользовательский интерфейс не обновляется в случае изменения имиджа сотрудника. Как это сделать?

1 Ответ

1 голос
/ 12 октября 2019

В вашем коде есть несколько проблем.

  • Employee Модель

    • Ваша модель должна быть структурой.
    • Нет необходимости соответствовать ObservableObject.
    • Почему вы используете UIImage !? Просто используйте Image и, возможно, URL, если вы извлекаете данные из веб-интерфейса API асинхронно.
    • что-то вроде:

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

Для получения дополнительной информации вы можете проверить это out. Это было сделано в значительной степени, что вы собираетесь достичь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...