SwiftUI 通用数组模型

Posted

技术标签:

【中文标题】SwiftUI 通用数组模型【英文标题】:SwiftUI Generic Array Model 【发布时间】:2021-07-25 22:32:08 【问题描述】:

我有一个 Binding 变量,我正在尝试将其设为 Generi Array。我将在其中采用两个不同的模型,并且我想达到模型中的图像属性。我该怎么做?

我在不同的页面转换中使用了两种不同的模型。 如何使保存模型的数组通用?

模型 1

struct PoliceSignContainer: Codable, Hashable 
    var policeQuestions: [PoliceSign]?


enum PoliceSignSectionType: String, Codable, Hashable 
    case A = "A"
    case B = "B"
    case C = "C"


struct PoliceSign: Codable, Hashable 
    var id: Int?
    var image: String?
    var sections: [PoliceSignSectionType.RawValue : String]?
    var correct: String?

模型 2

struct TrafficSignContainer: Codable, Hashable 
    var trafficQuestions: [TrafficSign]?


enum TrafficSignSectionType: String, Codable, Hashable 
    case A = "A"
    case B = "B"


struct TrafficSign: Codable, Hashable 
    var id: Int?
    var image: String?
    var sections: [TrafficSignSectionType.RawValue : String]?
    var correct: String?




struct QuestionCardView: View 
    @EnvironmentObject var optionConfigure: OptionConfigure
    @Binding var questions: [Any]
    var body: some View 

        VStack 

            ....

            ZStack 
                ForEach((questions.indices).reversed(), id: \.self)  index -> AnyView in

                    let relativeIndex = index - optionConfigure.step
                    switch relativeIndex 
                    case 0...2:
                        return AnyView(

              ImageCard(image: .constant("\(questions[index].image ?? "p1")")) // here
                          ...

                        )
                    default:
                        return AnyView(EmptyView())
                    
                
            
            .animation(.spring())
            OptionView()
        
        ...
    

【问题讨论】:

这能回答你的问题吗? Is it possible to make SwiftUI ListMenu with different behaviors? 您是指同时有两个不同的模型(异构集合),还是视图的每个实例都为数组采用一种类型? @jnpdx 不能同时使用两个模型。 【参考方案1】:

为了使您的 Binding 数组又名问题变得通用,您只需符合 Hashable,访问符合 CustomStringConvertible 的字符串即可。查看示例代码:

struct QuestionCardView<T: Hashable & CustomStringConvertible>: View 
    @EnvironmentObject var optionConfigure: OptionConfigure
    @Binding var questions: [T]
    var body: some View 
        Text("")
        VStack 

            ....

            ZStack 
                ForEach((questions.indices).reversed(), id: \.self)  index -> AnyView in

                    let relativeIndex = index - optionConfigure.step
                    switch relativeIndex 
                    case 0...2:
                        return AnyView(

              ImageCard(image: String(describing: questions[index].image) ?? "p1")")) // here
                          ...

                        )
                    default:
                        return AnyView(EmptyView())
                    
                
            
            .animation(.spring())
            OptionView()
        
        ...
    

工作示例:

struct ContentView: View 
    
    @State private var array: [String] = [ "applelogo", "alarm", "person.fill.questionmark", "cloud.drizzle.fill", "swift"]
    
    var body: some View 

        CustomView(array: $array)
        
    
    




struct CustomView<T: Hashable & CustomStringConvertible>: View 
    
    @Binding var array: [T]
    
    var body: some View 
        

        VStack 
            
            ForEach(array, id:\.self)  item in

                ImageView(imageString: String(describing: item))
                
            
            
        
        
    
    


struct ImageView: View 
    
    let imageString: String
    
    var body: some View 
        
        Image(systemName: imageString)
            .resizable()
            .scaledToFit()
            .frame(width: 50, height: 50, alignment: Alignment.center)
        
    
    

【讨论】:

单独设置Hashable 不允许访问以ImageCard 开头的行上的image 属性 是的,它也需要符合CustomStringConvertible CustomStringConvertable 没有 image 属性。 都可以看例子! @UfukKöşker:我无权访问您的项目,我无法以这种方式帮助您,请查看示例并采纳想法。 我现在明白了。我会再试试你的代码。【参考方案2】:

这是一个基本示例,显示了一个对 @Binding 数组有一般要求的视图,就像你有的那样:


enum TrafficSignSectionType: String, Codable, Hashable 
    case A = "A"
    case B = "B"


struct TrafficSign: Codable, Hashable, Question  //<-- Here
    var id: Int?
    var image: String?
    var sections: [TrafficSignSectionType.RawValue : String]?
    var correct: String?


enum PoliceSignSectionType: String, Codable, Hashable 
    case A = "A"
    case B = "B"
    case C = "C"


struct PoliceSign: Codable, Hashable, Question  //<-- Here
    var id: Int?
    var image: String?
    var sections: [PoliceSignSectionType.RawValue : String]?
    var correct: String?



protocol Question : Identifiable  //<-- Here
  var image: String?  get set 


struct ContentView : View 
    @State private var questions : [PoliceSign] = []
    @State private var questions2 : [TrafficSign] = []
    
    var body: some View 
        QuestionCardView(questions: $questions)
        QuestionCardView(questions: $questions2)
    


struct QuestionCardView<T: Question>: View 
    @Binding var questions: [T]
 
    var body: some View 
        ForEach(questions)  question in
            Text(question.image ?? "")
        
    

您需要一个定义类型要求的protocol。在您的原始代码中,看起来 image 是唯一明显的属性。

您的原始代码将具有:

struct QuestionCardView<T: Question>: View 
    @EnvironmentObject var optionConfigure: OptionConfigure
    @Binding var questions: [Question]

【讨论】:

我编辑了我的问题,先生。可以查一下吗? 我已经更新了我的答案。您需要做的就是添加Question 协议,然后确保两个模型都符合它。不需要容器类型。除了将image 设为Optional 属性之外,它与我之前的答案版本基本相同。 非常感谢您的回答,但先生,我没有什么问题。我需要在协议中添加两个不同的枚举。我怎样才能做到这一点 ?因为在打开的下一页中,我需要访问 Enums。 @UfukKöşker 我不确定这到底是什么意思。如果您觉得它与原始问题直接相关,可以编辑问题以添加更多信息来解释它。不过,这实际上听起来可能是一个新问题。如果您发现此答案有帮助,请考虑对其进行投票。 如果您的意思是sections 属性,因为您已将其设置为以enums 的原始值作为键的字典,您只需将var sections: [String:String]? get set 添加到协议中即可.

以上是关于SwiftUI 通用数组模型的主要内容,如果未能解决你的问题,请参考以下文章

如何将字符串数组从视图模型传递到 swiftUI 中播放歌曲

视图模型数组上的 ForEach 循环问题导致 Xcode 编译错误 - SwiftUI

编写 SwiftUI 模型以从带有数组的 JSON 文件中读取

SwiftUI - 列出嵌套数组中的元素

将数据从模型传递到 SwiftUI 中的视图

SwiftUI |在所有视图中可用的模型或类中创建错误消息