prabhu
prabhu

Reputation: 1206

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

Upvotes: 3

Views: 2753

Answers (4)

SreekanthI
SreekanthI

Reputation: 433

We can use protocol and send any enum object and no need to type cast the object to access the 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")])

Upvotes: 0

Ahmad F
Ahmad F

Reputation: 31645

For applying abstraction, you could use protocol, as follows:

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:

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

For instance, a function that takes a parameter as array of Menus should work:

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:

class  MyClass {
    ...

    var menu: Menu?

    ...
}

Upvotes: 2

XmasRights
XmasRights

Reputation: 1509

You need a way to connect the two enums, which could be a common Menu protocol. The problem you'll face there is the type erasure involved in passing the Menu object around. 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
  3. The associated data type of new menus could be anything (structs, images, nested submenus, etc)
  4. No optionals - only concrete types

Upvotes: 1

Mohammad Sadiq
Mohammad Sadiq

Reputation: 5241

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.

Upvotes: 1

Related Questions