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

SwiftUI项目中如何泛化多个存在重复逻辑的ViewModel?

解决方案

你可以通过以下两种常用方案实现代码复用:

方案1:泛型基类继承(最贴合你的初始需求)

直接定义通用泛型父类,把可变的选择类型作为泛型参数,所有公共逻辑统一放在父类实现,子类仅需定义独有业务内容即可:

// 通用基类
class BaseViewModel<SelectionType>: ObservableObject {
    @Published var selected: SelectionType?
    
    func select(_ value: SelectionType?) {
        selected = value
    }
}

// 业务子类A
class ViewModelA: BaseViewModel<ViewModelA.Animal> {
    enum Animal {
        case cat
        case dog
    }
    // 仅需编写ViewModelA独有的逻辑
}

// 业务子类B
class ViewModelB: BaseViewModel<ViewModelB.Animal> {
    enum Animal {
        case lion
        case tiger
    }
    // 仅需编写ViewModelB独有的逻辑
}

该方案代码量最少,完全复用父类的属性与方法实现,不需要重复编写公共逻辑。

方案2:带关联类型的协议实现(适用无法使用继承的场景)

虽然Swift协议不能直接声明属性包装器,但可以声明@Published生成的对应属性,再通过协议扩展提供默认方法实现:

// 通用协议定义
protocol SelectableViewModel: ObservableObject {
    associatedtype SelectionType
    var selected: SelectionType? { get set }
    var $selected: Published<SelectionType?>.Publisher { get }
}

// 协议默认实现公共方法
extension SelectableViewModel {
    func select(_ value: SelectionType?) {
        selected = value
    }
}

// 业务实现A
class ViewModelA: SelectableViewModel {
    enum Animal {
        case cat
        case dog
    }
    // 添加@Published标记即可自动满足协议要求
    @Published var selected: Animal?
    // 其他独有逻辑
}

// 业务实现B
class ViewModelB: SelectableViewModel {
    enum Animal {
        case lion
        case tiger
    }
    @Published var selected: Animal?
    // 其他独有逻辑
}

注意:你示例代码中的@published为拼写错误,正确的属性包装器名称为首字母大写的@Published。

内容的提问来源于stack exchange,提问作者G. Marc

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 11:24:04