简体   繁体   English

Swift - 将同一变量的不同枚举类型传递给一个类

[英]Swift - Passing different enum types for same variable to a class

How can I pass different enums types to a same variable, identify its type later and use its raw values to do some operations?如何将不同的枚举类型传递给同一个变量,稍后识别其类型并使用其原始值进行一些操作?

I have two enums Menu1 and Menu2 of type String.我有两个字符串类型的枚举Menu1Menu2 I like to pass an array of enums to another class which shows submenu.我喜欢将枚举数组传递给另一个显示子菜单的类。 I like to pass enum to same variable since I may add another menu in future.我喜欢将 enum 传递给同一个变量,因为我将来可能会添加另一个菜单。

For applying abstraction, you could use protocol , as follows:为了应用抽象,您可以使用protocol ,如下所示:

protocol Menu {}

enum Menu1: String, Menu {
    case option1 = "Option 01 From Menu 01"
    case option2 = "Option 02 From Menu 01"
    case option3 = "Option 03 From Menu 01"
    case option4 = "Option 04 From Menu 01"
    case option5 = "Option 05 From Menu 01"
}

enum Menu2: String, Menu {
    case option1 = "Option 01 From Menu 02"
    case option2 = "Option 02 From Menu 02"
    case option3 = "Option 03 From Menu 02"
    case option4 = "Option 04 From Menu 02"
    case option5 = "Option 05 From Menu 02"
}

By implementing this, you are able to declare arrays of Menu type, which include both of the enums:通过实现这一点,您可以声明Menu类型的数组,其中包括两个枚举:

let myMenu1Array: [Menu1] = [.option1, .option2, .option5]
let myMenu2Array: [Menu2] = [.option1, .option3, .option4]

For instance, a function that takes a parameter as array of Menu s should work:例如,一个将参数作为Menu数组的函数应该可以工作:

func handleMenu(_ menuArray: [Menu]) {
    if let menu1Array = menuArray as? [Menu1] {
        print("Menu 1 Detected!")

        // you could iterate through it for instance...
        for option in menu1Array {
            print(option.rawValue)
        }

        return
    }

    if let menu2Array = menuArray as? [Menu2] {
        print("Menu 2 Detected!")

        // you could iterate through it for instance...
        for option in menu2Array {
            print(option.rawValue)
        }

        return
    }
}

The output would be:输出将是:

handleMenu(myMenu1Array)
/*
 Menu 1 Detected!
 Option 01 From Menu 01
 Option 02 From Menu 01
 Option 05 From Menu 01
 */

handleMenu(myMenu2Array)
/*
 Menu 2 Detected!
 Option 01 From Menu 02
 Option 03 From Menu 02
 Option 04 From Menu 02
 */

So, if you have a property in a class that should represents a menu, you could declare it as a type of Menu :因此,如果类中有一个属性应该代表菜单,则可以将其声明为Menu类型:

class  MyClass {
    ...

    var menu: Menu?

    ...
}

You can declare one protocol, that the two enums should conform to.您可以声明一个协议,这两个枚举应该符合。 Now accept in your function parameter that confirms to the protocol.现在接受确认协议的函数参数。 Alternatively you can make use of generics.或者,您可以使用泛型。

You need a way to connect the two enums, which could be a common Menu protocol.您需要一种连接两个枚举的方法,这可能是一个通用的Menu协议。 The problem you'll face there is the type erasure involved in passing the Menu object around.您将面临的问题是传递Menu对象所涉及的类型擦除。 It's far too easy to add a new menu type, and not check for it everywhere in your code.添加新的菜单类型太容易了,而不是在代码中到处检查它。

I suggest a small refactor, wrapping each into a another enum, managed by a common struct.我建议进行一个小的重构,将每个都包装到另一个由公共结构管理的枚举中。

enum Menu1: String {
    case option1 = "Option 01 From Menu 01"
    case option2 = "Option 02 From Menu 01"
    case option3 = "Option 03 From Menu 01"
    case option4 = "Option 04 From Menu 01"
    case option5 = "Option 05 From Menu 01"
}

enum Menu2: String {
    case option1 = "Option 01 From Menu 02"
    case option2 = "Option 02 From Menu 02"
    case option3 = "Option 03 From Menu 02"
    case option4 = "Option 04 From Menu 02"
    case option5 = "Option 05 From Menu 02"
}

struct Menu
{
    enum MenuType
    {
        case one (Menu1)
        case two (Menu2)
    }

    let type: MenuType
}


func handle(menu: Menu)
{
    switch menu.type
    {
    case .one(let data): print (data.rawValue)
    case .two(let data): print (data.rawValue)
    }
}

let menu = Menu(type: .one(Menu1.option1))
handle(menu: menu)

The key advantages to this method:这种方法的主要优点:

  1. You can arbitrarily keep adding menus可以任意不断添加菜单
  2. Any time you add a new menu type, all the switch statements in your code will kick in a compile time error, showing you where you need to update your code任何时候添加新的菜单类型时,代码中的所有 switch 语句都会引发编译时错误,显示需要更新代码的位置
  3. The associated data type of new menus could be anything (structs, images, nested submenus, etc)新菜单的关联数据类型可以是任何东西(结构、图像、嵌套子菜单等)
  4. No optionals - only concrete types没有选项 - 只有具体类型

We can use protocol and send any enum object and no need to type cast the object to access the rawValue.我们可以使用协议并发送任何枚举对象,而无需对对象进行类型转换来访问 rawValue。 we can pass different types of enums and read the values.我们可以传递不同类型的枚举并读取值。

protocol AttributeKeyProtocol {
    var value: String { get }
}

struct AttributeData {
     let key: AttributeKeyProtocol
     let value: String
     init(key: AttributeKeyProtocol, value: String) {
        self.key = key
        self.value = value
    }
}

enum MyClasses: AttributeKeyProtocol {
    var value: String {
        switch self {
        case .one(.logo):
            return"logo"
        default:
            return "all"
        }
    }
    
    case one(MyComputerClasses)
    case two
    
    enum MyComputerClasses: String, AttributeKeyProtocol {
        case logo
        case pascal
        
        var value: String {
            return self.rawValue
        }
    }
}

MyClasses implementing 'AttributeKeyProtocol'


enum MyCourses: String, AttributeKeyProtocol {
    case three = "psd_ssj_sdoj"
    case four
    
    var value: String {
        return self.rawValue
    }
}

class NewSDK {
    func track(name: String, type: String, attributes: [AttributeData]?) {
        print("attributes:  \(attributes?.first?.key.value)")
        print("attributes:  \(attributes?.last?.key.value)")
    }
}

NewSDK().track(name: "sfd", type: "dsfd", attributes: [.init(key: MyClasses.one(.logo) , value: "sdfd"),
                                                         .init(key: MyCourses.three, value: "sfdfsd")])

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

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