微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

快速遍历不同变量类型的ForEach循环

如何解决快速遍历不同变量类型的ForEach循环

我正在努力解决一个我认为(希望)有一个简单的解决方法的问题,您可能可以提供帮助。

我正在尝试对多个变量运行ForEach循环。为了使事情简单,我只包含了两个变量,但还有更多变量,因此为什么我要使用ForEach循环而不是为每个变量重复相同的代码。每个变量都基于不同的枚举。

预期结果

我想在我的代码中运行一个ForEach循环,该循环遍历变量数组并提取变量的描述和关联的rawValue。

变量

var profileEyeColor: EyeColor = EyeColor()
var profileHairColor: HairColor = HairColor()

枚举

enum EyeColor: String,CaseIterable {
    case notSet
    case Amber
    case blue
    case brown
    case gray
    case green
    case hazel
    case other
    case witheld
    
    var description: String {
        "Eye Color"
    }
    
    init() {
        self = .notSet
    }
}
enum HairColor: String,CaseIterable {
    case notSet
    case black
    case blond
    case brown
    case auburn
    case red
    case gray
    case white
    case other
    case witheld
    
    var description: String {
        "Hair Color"
    }
    
    init() {
        self = .notSet
    }
}

ForEach循环

ForEach([profileEyeColor,profileHairColor],id: \.self) { item in
   if item != .notSet && item != .witheld {
       print(item.description)
       print(item.rawValue)
   }
}

实际结果

构建失败,xCode错误包括

  • 无法将'profileHairColor'类型的值转换为预期的元素类型'EyeColor'

尝试替代

我尝试使用for循环而不是ForEach来运行。我正在使用SwiftUI,因此无法在主体内实现for循环。 我也尝试将其拆分为一个单独的函数,但在该函数上出现错误

func profileDetailsLoop(data: [Any]) -> View {
   ForEach(data,id: \.self) { item in
      if item != .notSet && item != .witheld {
         HStack {
            Text(item.description)
            Text(item.rawValue)
       }
   }
}

错误:协议类型“ Any”的值不符合“ Hashable”;只有struct / enum / class类型可以符合协议

如果将[Any]替换为[enum],则会出现以下错误:预期的元素类型

如果我用任何特定的枚举类型(例如[Any])将[EyeColor]替换为无效的(并且可能也不适用于不同的枚举类型)。

解决方法

ForEach有某些要求,它喜欢对Identifiable个项目的集合进行迭代。考虑到这一点,让我们提供每个属性可以提供的struct Attribute

struct Attribute: Identifiable {
    let name: String
    let value: String
    let id = UUID()
}

您可以将计算所得的var手动添加到提供此属性的每个枚举中,但这将是很多重复的代码。

相反,让我们注意,所有属性都提供了rawValuedescription,而这正是初始化Attribute所需的全部。

定义此协议:

protocol AttributeType {
    var rawValue: String { get }
    var description: String { get }
}

然后将此extension创建为返回Attribute的协议:

extension AttributeType {
    var attribute: Attribute? {
        guard self.isSet else { return nil }
        return Attribute(name: self.description,value: self.rawValue)
    }
    
    var isSet: Bool { return !["notSet","witheld"].contains(self.rawValue) }
}

最后,让您所有的枚举都采用AttributeType

enum EyeColor: String,CaseIterable,AttributeType {
    case notSet
    case amber
    ...
    
    var description: String {
        "Eye Color"
    }
    
    init() {
        self = .notSet
    }
}


enum HairColor: String,AttributeType {
    case notSet
    case black
    ...
    
    var description: String {
        "Hair Color"
    }
    
    init() {
        self = .notSet
    }
}

然后,您可以通过访问Attribute属性来为每个属性获取.attribute

ForEach([profileEyeColor.attribute,profileHairColor.attribute].compactMap { $0 }) { attribute in
    HStack {
        Text(attribute.name)
        Text(attribute.value)
    }
}

为避免为数组中的每个 属性键入.attribute,可以这样编写:

ForEach([profileEyeColor as AttributeType,profileHairColor].compactMap { $0.attribute }) {

这将节省大量的属性列表输入。

注释:

  • .attribute返回可选 Attribute。如果属性是nil.notSet,则为.witheld
  • .compactMap { $0 }用于删除nil值并为[Attribute]创建ForEach以便迭代。
  • 由于AttributeIdentifiable,因此它提供了id,因此没有必要明确声明。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。