You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 15:00:58