Home > Blockchain >  Use enum as dictionary key in delegate methods
Use enum as dictionary key in delegate methods

Time:01-25

I currently have messaging between an iOS app and WatchOS app happening. I am using a hardcoded string of message for the key. This works, but I want to have several types of messages. So I made an enum with type of String.

enum DeviceMessage: String {
    case Foo, Bar
}

In a view I want to call the WCSession send a message using my own method:

func sendMessage(msg:[String : Any]){
    if self.session.isReachable == false {
        self.session.transferUserInfo(msg)
    } else {
        self.session.sendMessage(msg, replyHandler: nil){ error in
            print(error.localizedDescription)
        }
    }
} 

Instead of String for the dictionary key, I want to be able to use .Foo. Without using RawValue, etc. What is the best way to set this up? In this vein, I would also like to set my delegate method for incoming messages to use DeviceMessage as a key too so I can evaluate it without using hardcoded strings for the keys.

func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) {
    print(message)
    DispatchQueue.main.async {
        self.message = userInfo["message"] as? String ?? "Unknown"
    }
}

CodePudding user response:

I added this to the file where my enum lives:

func DeviceMessageRawKey(key: DeviceMessage) -> String { return key.rawValue }

So now I can send and receive using String (no changes) but when being specific, I can use the enum.

func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
    DispatchQueue.main.async {
        if let val = message[DeviceMessageRawKey(key: .Foo)] {
            self.message = val as? String ?? "Unknown"
        }
    }
}

...

self.model.sendMessage(msg: [DeviceMessageRawKey(key: .Foo) : "Need data."])

CodePudding user response:

The only thing required for something to be a dictionary key is that it implements the Hashable protocol. Since your enum has a raw value of type String, you can just have it conform to the protocol and not implement anything.

enum DeviceMessage: String, Hashable {
    case Foo, Bar
}

You can then do:

let dict: [DeviceMessage: Any] = [.Foo: "hello"]

You will still need to convert from [String: Any] -> [DeviceManager: Any] (and vice versa) somewhere, but at least you can work with just [DeviceManager: Any] outside of the class that sends/receives messages.

  • Related