Удалить объекты из ObservableObject

Два ViewModels, один магазин roles содержащий skills:

final class RolesStore: ObservableObject {
  @Published var roles: [Role] = []
.....

Образцом для подражания является:

struct Role: Codable, Identifiable {
    let id: String
    var name: String
    var skills: [Skill]
}

Другой ViewModel это магазин skills:

final class SkillStore: ObservableObject {
    @Published var skills: [Skill] = []
.....

Ниже показано, что я хочу сделать, удалить навык из SkillStore (удобно), а также автоматически удалить удаленный навык из любого role у которых есть навыки в RoleStore:

Как видите, сняв навык handy не удаляет его из роли Ansatt. Я не уверен, как это сделать, поэтому я подготовил площадку для игры Xcode, которую можно клонировать с Github: https://github.com/imyrvold/roleSkills

Должен быть способ получить SkillStore имея зависимость от навыков в SkillStore или нет другого способа, кроме как перебрать все роли и удалить навык из всех ролей, которые обладают этим навыком?

1 ответ

Я нашел решение этого, когда вспомнил, что класс может подписаться на изменения в другом классе с помощью магии Combine. Итак, если бы я могRoleStore класс подписаться на изменения в SkillStore, тогда RoleStore может обновлять и удалять навык в своих ролях, когда пользователь удаляет навык.

Для этого RolesStore должна быть ссылка на SkillStore:

import SwiftUI
import PlaygroundSupport

var skillStore = SkillStore(skills: MySkills.skills())
var roleStore = RoleStore(roles: MyRoles.roles(), skillStore: skillStore)

struct ModelsView: View {
    @ObservedObject var skillStore: SkillStore
    @ObservedObject var roleStore: RoleStore
....

SkillStore обновляется PassthroughSubject который отправит удаленный навык (deletedPublisher):

import Foundation
import Combine

public final class SkillStore: ObservableObject {
    @Published public var skills: [Skill] = [] {
        didSet {
            let oldSkills = Set(oldValue)
            let uniqueSet = oldSkills.subtracting(self.skills)
            if let deletedSkill = uniqueSet.first {
                deletedPublisher.send(deletedSkill)
            }
        }
    }
    private var cancellables: Set<AnyCancellable> = []
    let deletedPublisher = PassthroughSubject<Skill, Never>()

    public init(skills: [Skill]) {
        self.skills = skills
    }

    public func delete(skills: [Skill]) {
        for skill in skills {
            if let index = self.skills.firstIndex(where: { $0 == skill }) {
                self.skills.remove(at: index)
            }
        }
    }
}

и наконец RoleStore удаляет удаленный навык из всех ролей, имеющих этот навык:

import Foundation
import Combine
import SwiftUI

public final class RoleStore: ObservableObject {
    @Published public var roles: [Role] = []
    @ObservedObject var skillStore: SkillStore
    private var cancellables: Set<AnyCancellable> = []

    public init(roles: [Role], skillStore: SkillStore) {
        self.roles = roles
        self.skillStore = skillStore
        self.skillStore.deletedPublisher.sink { skill in
            for roleIndex in self.roles.indices {
                let skills = self.roles[roleIndex].skills.filter { $0 != skill }
                self.roles[roleIndex].skills = skills
            }
        }
        .store(in: &cancellables)
    }
}

Я обновил Playground внесенными изменениями.

Другие вопросы по тегам