如何在Swift中创建ObservableObjects的通用持久化数组
解决PersistentArray通用版的ObservableObject变更绑定错误
问题根源
ObservableObject协议的objectWillChange是关联类型的发布者,其Output类型默认是Void,但自定义的ObservableObject可以指定其他类型的Output。你的通用版代码中直接尝试将任意Object的objectWillChange赋值给Published<Void>的存储属性,导致类型不匹配——因为Object.ObjectWillChangePublisher.Output不一定等于Void。
修复方案
我们不需要关心objectWillChange的具体输出值,只需要感知到变更事件。因此可以将每个对象的objectWillChange输出转换为Void,再同步到自身的objectWillChange发布者,避免类型不匹配问题。
完整示例代码
import Combine import SwiftUI class PersistentArray<Object: ObservableObject>: ObservableObject { @Published private(set) var items: [Object] private var cancellables = [ObjectIdentifier: AnyCancellable]() // 用字典跟踪每个对象的订阅,方便移除时取消 init(items: [Object]) { self.items = items setupItemBindings() } // 绑定已有对象的变更事件 private func setupItemBindings() { items.forEach { bindObject($0) } } // 绑定单个对象的变更事件 private func bindObject(_ object: Object) { let id = ObjectIdentifier(object) cancellables[id] = object.objectWillChange .map { _ in () } // 将任意类型的Output转换为Void .sink(receiveValue: { [weak self] _ in self?.objectWillChange.send(()) // 触发自身的变更通知 self?.save() // 自动执行持久化保存 }) } // 添加元素并绑定变更 func add(_ item: Object) { items.append(item) bindObject(item) save() } // 移除元素并取消订阅 func remove(_ item: Object) { guard let index = items.firstIndex(where: { ObjectIdentifier($0) == ObjectIdentifier(item) }) else { return } items.remove(at: index) let id = ObjectIdentifier(item) cancellables.removeValue(forKey: id) save() } // 持久化保存逻辑(根据你的需求实现) private func save() { // 示例:用UserDefaults保存(实际项目建议用更可靠的存储方案) if let data = try? JSONEncoder().encode(items) { UserDefaults.standard.set(data, forKey: "PersistentArray_Items") } } }
关键说明
- 用
map { _ in () }将任意类型的objectWillChange输出转换为Void,统一事件类型 - 使用
[ObjectIdentifier: AnyCancellable]跟踪每个对象的订阅,避免数组元素移除后出现内存泄漏 - 在对象变更时触发自身的
objectWillChange.send(()),确保视图能感知到数组内元素的变化并刷新 - 同步调用
save()方法完成持久化存储
内容的提问来源于stack exchange,提问作者mstrsn
相关产品推荐
相关产品推荐

