简体   繁体   English

如何使枚举符合 Swift 中的可识别协议?

[英]How to conform an enumeration to Identifiable protocol in Swift?

I'm trying to make a list with the raw values of the cases from an enumeration with the new SwiftUI framework.我正在尝试使用新的SwiftUI框架从枚举中列出案例的原始值。 However, I'm having a trouble with conforming the 'Data' to Identifiable protocol and I really cannot find information how to do it.但是,我在将“数据”符合可识别协议时遇到了麻烦,我真的找不到如何做到这一点的信息。 It tells me "Initializer 'init(_:rowContent:)' requires that 'Data' conform to 'Identifiable'" The stub provides me with an ObjectIdentifier variable in the last extension, but don't know what should I return.它告诉我“Initializer 'init(_:rowContent:)' 要求 'Data' 符合 'Identifiable'” 存根在最后一个扩展中为我提供了一个 ObjectIdentifier 变量,但不知道我应该返回什么。 Could you tell me how do it?你能告诉我怎么做吗? How do I conform Data to Identifiable, so I can make a list with the raw values?如何使 Data 符合 Identifiable,以便我可以使用原始值制作一个列表?

enum Data: String {
    case firstCase = "First string"
    case secondCase = "Second string"
    case thirdCase = "Third string"
}

extension Data: CaseIterable {
    static let randomSet = [Data.firstCase, Data.secondCase]
}

extension Data: Identifiable {
    var id: ObjectIdentifier {
        return //what?
    }

}

//-------------------------ContentView------------------------
import SwiftUI

struct Lala: View {
    var name: String

    var body: some View {
        Text(name)
    }
}

struct ContentView: View {
    var body: some View {
        return List(Data.allCases) { i in
            Lala(name: i.rawValue)
        }
    }
}

⚠️ Try not to use already used names like Data for your internal module. ⚠️ 尽量不要在内部模块中使用已经使用过的名称,例如Data I will use MyEnum instead in this answer我将在这个答案中使用MyEnum


When something conforms to Identifiable , it must return something that can be identified by that.当某些东西符合Identifiable ,它必须返回可以通过它识别的东西。 So you should return something unique to that case.所以你应该返回一些独特的东西。 For String base enum , rawValue is the best option you have:对于String base enumrawValue是您拥有的最佳选择:

extension MyEnum: Identifiable {
    var id: RawValue { rawValue }
}

Also, enum s can usually be identified by their selves:此外, enum通常可以通过它们自己来识别:

extension MyEnum: Identifiable {
    var id: Self { self }
}

⚠️ Note 1 : If you return something that is unstable, like UUID() or an index , this means you get a new object each time you get the object and this will kill reusability and can cause epic memory and layout process usage beside view management issues like transition management and etc. ⚠️ 注意 1 :如果你返回一些不稳定的东西,比如UUID()索引,这意味着你每次获取对象时都会得到一个新对象,这将扼杀可重用性,并可能导致除视图管理之外的史诗内存和布局过程使用过渡管理等问题。

Take a look at this weird animation for adding a new pet:看看这个添加新宠物的奇怪动画: UUID 示例

Note 2 : From Swift 5.1, single-line closures don't need the return keyword.注 2 :从 Swift 5.1 开始,单行闭包不需要return关键字。

Note 3 : Try not to use globally known names like Data for your own types.注意 3 :尽量不要对自己的类型使用像Data这样的全球知名名称。 At least use namespace for that like MyCustomNameSpace.Data至少使用命名空间,比如MyCustomNameSpace.Data


Inline mode内联模式

You can make any collection iterable inline by one of it's element's keypath:您可以通过其元素的键路径之一使任何集合可迭代内联

For example to self :例如self

List(MyEnum.allCases, id:\.self)

or to any other compatible keypath:或任何其他兼容的键路径:

List(MyEnum.allCases, id:\.rawValue)

✅ The checklist of the identifier: (from WWDC21) ✅ 标识符的清单:(来自 WWDC21)

  • Exercise caution with random identifiers.谨慎使用随机标识符。
  • Use stable identifiers.使用稳定的标识符。
  • Ensure the uniqueness, one identifier per item.确保唯一性,每个项目一个标识符。

You can try this way:你可以试试这个方法:

enum MyEnum: Identifiable {
    case valu1, valu2
    
    var id: Int {
        get {
            hashValue
        }
    }
}

Another approach with associated values would be to do something like this, where all the associated values are identifiable.另一种关联值的方法是做这样的事情,其中​​所有关联的值都是可识别的。

enum DataEntryType: Identifiable {
    var id: String {
        switch self {
        case .thing1ThatIsIdentifiable(let thing1):
            return thing1.id
        case .thing2ThatIsIdentifiable(let thing2):
            return thing2.id
        }
    }
    
    case thing1ThatIsIdentifiable(AnIdentifiableObject)
    case thing2ThatIsIdentifiable(AnotherIdentifiableObject)

Copyright © 2021 Mark Moeykens.版权所有 © 2021 马克·莫伊肯斯。 All rights reserved.版权所有。 | | @BigMtnStudio Combine Mastery in SwiftUI book @BigMtnStudio 在 SwiftUI 书中结合精通

enum InvalidAgeError: String, Error , Identifiable {
    var id: String { rawValue }
    case lessThanZero = "Cannot be less than zero"
    case moreThanOneHundred = "Cannot be more than 100"
}

I'm trying to make a list with the raw values of the cases from an enumeration with the new SwiftUI framework.我正在尝试使用新的SwiftUI框架枚举列出案例的原始值。 However, I'm having a trouble with conforming the 'Data' to Identifiable protocol and I really cannot find information how to do it.但是,我在使“数据”符合可识别协议方面遇到了麻烦,我真的找不到信息。 It tells me "Initializer 'init(_:rowContent:)' requires that 'Data' conform to 'Identifiable'" The stub provides me with an ObjectIdentifier variable in the last extension, but don't know what should I return.它告诉我“ Initializer'init(_:rowContent :)'要求'Data'必须符合'Identifiable'”。存根在最后一个扩展名中为我提供了ObjectIdentifier变量,但不知道我应该返回什么。 Could you tell me how do it?你能告诉我怎么做吗? How do I conform Data to Identifiable, so I can make a list with the raw values?如何使数据符合可识别性,以便我可以列出原始值?

enum Data: String {
    case firstCase = "First string"
    case secondCase = "Second string"
    case thirdCase = "Third string"
}

extension Data: CaseIterable {
    static let randomSet = [Data.firstCase, Data.secondCase]
}

extension Data: Identifiable {
    var id: ObjectIdentifier {
        return //what?
    }

}

//-------------------------ContentView------------------------
import SwiftUI

struct Lala: View {
    var name: String

    var body: some View {
        Text(name)
    }
}

struct ContentView: View {
    var body: some View {
        return List(Data.allCases) { i in
            Lala(name: i.rawValue)
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM