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

SwiftUI泛型结构体的@ObservedObject定义报错求助

解决SwiftUI泛型结构体扩展ViewModel的实例化问题

问题根源

你遇到的错误是因为GenericViewModel是泛型结构体GenericView<T, U, V>的扩展类,它的实际类型是GenericView<T, U, V>.GenericViewModel——必须显式指定T、U、V的具体类型才能实例化。但你的场景里,ViewModel并不依赖GenericView的泛型参数,所以没必要把它放在扩展里。

推荐解决方案:将ViewModel改为独立类

把GenericViewModel从GenericView的扩展中移出,变成独立的ObservableObject类,这样就不需要绑定泛型参数,实例化会更简单,同时解耦ViewModel和View的泛型依赖。

修改后的GenericViewModel

import Foundation

class GenericViewModel: ObservableObject {
    @Published var someData = ""
    
    // 修复原初始化方法的无效赋值问题
    init() {}
}

修改后的GenericView

将原本的@StateObject改为外部传入的@ObservedObject,让ViewModel可以从父视图注入:

import SwiftUI

struct GenericView<T: Shape, U: Shape, V: View>: View {
    @ObservedObject var vm: GenericViewModel
    let shape1:  T
    let shape2:  U
    let color1:  Color
    let color2:  Color
    let color3:  Color
    let content: () -> V
    
    var body: some View {
        ZStack {
            HStack {
                shape1
                    .foregroundColor(color1)
                shape2
                    .foregroundColor(color2)
            }
            .overlay(
                VStack {
                    content()
                    Text(vm.someData)
                }
                    .foregroundColor(color3)
            )
        }
        .frame(width:  200,
               height: 100)
    }
}

修改后的ContentView

现在可以直接实例化GenericViewModel,不再需要处理泛型参数:

import SwiftUI

struct ContentView: View {
    @ObservedObject var vm = GenericViewModel()
    
    var body: some View {
        VStack {
            GenericView(vm:     vm,
                        shape1: Circle(),
                        shape2: Rectangle(),
                        color1: .black,
                        color2: .gray,
                        color3: .white) {
                           Text("Hello, world.")
                        }
            
            Button {
                vm.someData = "Hello back."
            } label: {
                Rectangle()
                    .overlay(
                        Text("Respond")
                            .foregroundColor(.black)
                            .bold()
                    )
                    .frame(width:  100,
                           height: 50)
            }
            .padding()
            
        }
    }
}

备选方案:保留扩展并显式指定泛型参数

如果必须把ViewModel留在GenericView扩展中,实例化时需要明确指定GenericView的泛型参数(对应你要创建的视图的形状和内容类型):

// 在ContentView中
@ObservedObject var vm = GenericView<Circle, Rectangle, Text>.GenericViewModel()

这种方式耦合性极高,一旦GenericView的参数类型变化,这里必须同步修改,仅适合ViewModel确实依赖GenericView泛型参数的场景。

内容的提问来源于stack exchange,提问作者user19537947

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 22:45:30