【问题标题】:Swift - Passing different enum types for same variable to a classSwift - 将同一变量的不同枚举类型传递给一个类
【发布时间】:2017-07-26 06:53:49
【问题描述】:

如何将不同的枚举类型传递给同一个变量,稍后识别其类型并使用其原始值进行一些操作?

我有两个字符串类型的枚举 Menu1Menu2。我喜欢将一个枚举数组传递给另一个显示子菜单的类。我喜欢将枚举传递给同一个变量,因为我将来可能会添加另一个菜单。

【问题讨论】:

  • 不能把两个枚举合并成一个枚举吗?
  • Any 可能会有所帮助,但您需要将其转换回您的 enum 类型。
  • 不。我喜欢把它分开,因为枚举值很高

标签: swift enums


【解决方案1】:

为了应用抽象,你可以使用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"
}

通过实现这一点,您可以声明Menu 类型的数组,其中包括两个枚举:

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

例如,将参数作为Menus 数组的函数应该可以工作:

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
    }
}

输出将是:

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
 */

所以,如果你在一个类中有一个属性应该代表一个菜单,你可以将它声明为Menu的类型:

class  MyClass {
    ...

    var menu: Menu?

    ...
}

【讨论】:

  • 您应该使用条件绑定 (if let menuArray = menuArray as [Menu1] ...) 而不是 is + as!
  • 哦,多么愚蠢的错误! @Alexander 感谢您的注意:) 已编辑。
  • 解决方案看起来不错。是否有可能避免类型转换并从协议注入对象中获取 rawValue?如果我有丹麦人的枚举怎么办,我必须为每种类型输入种姓并获得 rawValue?
【解决方案2】:

你可以声明一个协议,这两个枚举应该符合。 现在接受确认协议的函数参数。或者,您可以使用泛型。

【讨论】:

  • 如果您能展示上述可能性的示例,将会有所帮助。我是 swift 新手,我对枚举上的泛型和协议了解不多
【解决方案3】:

您需要一种方法来连接两个枚举,这可能是一个常见的Menu 协议。您将面临的问题是传递Menu 对象所涉及的类型擦除。添加新的菜单类型太容易了,而不是在代码中到处检查。

我建议进行一个小的重构,将每个都包装到另一个枚举中,由一个通用结构管理。

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)

这种方法的主要优点:

  1. 您可以任意继续添加菜单
  2. 每当您添加新的菜单类型时,代码中的所有 switch 语句都会引发编译时错误,向您显示需要更新代码的位置
  3. 新菜单的关联数据类型可以是任何东西(结构、图像、嵌套子菜单等)
  4. 没有可选项 - 只有具体类型

【讨论】:

    【解决方案4】:

    我们可以使用协议并发送任何枚举对象而无需键入 强制转换对象以访问 rawValue。我们可以通过不同类型的 枚举并读取值。

    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")])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-15
      • 1970-01-01
      • 2015-08-21
      • 1970-01-01
      • 2011-03-15
      • 1970-01-01
      相关资源
      最近更新 更多