1

Basically I'm using KVC, and have potentially different value types returned, and want to create a switch statement based on the type

I tried the answer here, but it wouldn't compile: Swift: Test class type in switch statement

        var value: String = "Unknown"
        switch node.value(forKeyPath: keyPath) {
        case let numberValue is NSNumber:
            if numberValue == 0 {
                value = "No"
            } else if numberValue == 1 {
                value = "Yes"
            }
        case let stringValue is String:
            value = stringValue
        default:
            break
        }

it says

"Pattern variable binding cannot appear in an expression"

and

"Cast from <> to unrelated 'NSNumber' always fails"

This code here works for me:

        var value: String = "Unknown"
        let nodeValue = node.value(forKeyPath: keyPath)
        switch nodeValue {
        case is NSNumber:
            if let numberValue = nodeValue as? NSNumber {
                if numberValue == 0 {
                    value = "No"
                } else if numberValue == 1 {
                    value = "Yes"
                }
            }
        case is String:
            if let stringValue = nodeValue as? String {
                value = stringValue
            }
        default:
            break
        }

but it seems a little un-optimal that I need to use optional bindings to typecast a new variable

Is there a better way to do this?

A O
  • 5,516
  • 3
  • 33
  • 68
  • that appears to create another problem, "binary operator can't be applied to "Any?" and "NSNumber" – A O Oct 03 '17 at 01:48
  • before entering the switch, try using `guard` on the value received from your `valueForKeyPath`. After that, you won't need to typecast. – Shamas S Oct 03 '17 at 01:50

2 Answers2

2

There is a way to pattern match and cast all at once, and I think it's actually quite clean:

switch nodeValue {
case let number as NSNumber:
    switch number {
    case 0: value = "No"
    case 1: value = "Yes"
    default: break
    }
case let string as String:
    value = string
default: break
}
andyvn22
  • 14,696
  • 1
  • 52
  • 74
0

Something like this should work

guard let unwrappedValue = node.value(forKeyPath: keyPath) else {
   return
}

switch (unwrappedValue) {
   case is String:
       value = (unwrappedValue as! String)
   case is NSNumber:
       value = (unwrappedValue as! NSNumber) == 0 ? "YES" : "NO"
   defualt:
       value = "default value?"
}
Shamas S
  • 7,507
  • 10
  • 46
  • 58