首页 > 解决方案 > 我可以在 SwiftUI 的状态变量中使用泛型类型吗?

问题描述

有没有办法在 Swift 的状态变量中使用泛型类型?

我有一个显示 3 个按钮的视图。每个按钮加载一个或类型的项目数组,MyGenericObject<TypeA>目的是然后显示所选数组中的对象列表。MyGenericObject<TypeB>MyGenericObject<TypeC>

但是当我写的时候 XCode 会抛出一个错误@State var objects: [MyGenericObject<T>]?

即使使用单个对象而不是数组,也会出现错误,如下例所示:

struct ObjectView: View {

// I would like the following to be @State var object: MyGenericObject<T> instead...
    
@State var object: MyGenericObject<TypeA>? 
    
    var body: some View {
        
        Text("\(object?.data.name)")

// because I would then like to do something like this, if possible:

    if type(of: object) == MyGenericObject<TypeA> {
        ...show list of item of this type
    } else

    if type(of: object) == MyGenericObject<TypeB> {
        ...show list of item of this type
    }

    else {
        ...show list of item of type MyGenericObject<TypeC>
    }

// or better yet, use a switch

}

如何在 SwiftUI 的 @State 变量中使用泛型类型?有没有更好的方法来实现我想要的?

标签: swiftswiftui

解决方案


我偶然发现了这个问题,并查看了要点。很难判断这是否正是您想要的,但似乎它可能会让您走上正确的道路:

protocol InstrumentType {
    var name : String { get set }
    var int : Int { get set }
    var bool : Bool { get set }
}

class Instrument<T : InstrumentType>: ObservableObject {
    @Published var object: T
    
    init(object: T){
        self.object = object
    }
}

class Trumpet: NSObject, ObservableObject, InstrumentType {
    @Published var name: String
    @Published var int: Int
    @Published var bool: Bool
    
    init(name: String = "newTrumpet", int: Int = 1, bool: Bool = true){
        self.name = name
        self.int = int
        self.bool = bool
    }
}

class Guitar: NSObject, ObservableObject, InstrumentType  {
    @Published var name: String
    @Published var int: Int
    @Published var bool: Bool
    
    init(name: String = "newGuitar", int: Int = 2, bool: Bool = true){
        self.name = name
        self.int = int
        self.bool = bool
    }
}

class Clarinet: NSObject, ObservableObject, InstrumentType  {
    @Published var name: String
    @Published var int: Int
    @Published var bool: Bool
    
    init(name: String = "newClarinet", int: Int = 3, bool: Bool = true){
        self.name = name
        self.int = int
        self.bool = bool
    }
}

struct ContentView : View {
    var body: some View {
        _ContentView(instrument: Instrument(object: Trumpet(name: "testTrumpet")))
    }
}

//VIEWS
struct _ContentView<T : InstrumentType>: View {
    @StateObject var instrument: Instrument<T>
    
    var body: some View {
        InstrumentView(instrument: instrument)
            .environmentObject(instrument)
            .frame(width: 300, height: 100)
    }
}

struct InstrumentView<T : InstrumentType>: View {
    
    @ObservedObject var instrument: Instrument<T>
    
    var body: some View {
        
        VStack {
            if type(of: instrument) == Instrument<Trumpet>.self {
                Text("Instrument is a trumpet")
                Text("\(instrument.object.name)")
                Text("\(instrument.object.int)")
                Text("\(instrument.object.bool ? "true" : "false")")
            } else
            
            if type(of: instrument) == Instrument<Guitar>.self {
                Text("Instrument is a guitar")
                Text("\(instrument.object.name)")
                Text("\(instrument.object.int)")
            }
            
            else {
                Text("Instrument is a clarinet")
            }
            
            Button("Update int") {
                instrument.object.int += 1
            }
        }  
    }
}
  1. 添加了一个协议,该协议InstrumentType定义了每台仪器上的可用属性——这让我可以摆脱Metadata,因为无论如何它都存储在每台仪器上

  2. 将每个泛型限制为InstrumentType

  3. 对于每种类型的仪器,我都感到有些困惑@StateObject——我假设我所做的可能就是您正在寻找的(一个通用的@StateObject,但也许这就是答案与意图不同的地方)

  4. 我能够以您希望的方式environmentObject使用object.name

  5. 添加了一个 Button 以显示 @Published 属性正确传播。


推荐阅读