Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write Dictionary extension that handles optional values

I'm trying to implement a Dictionary extension and I want to handle optional values. But whatever I do, if I use my method on a [String: String?] dictionary, it fails to optionally bind the value. How do you write an extension to a dictionary that gracefully handles optional values?


Consider the following extension:

extension Dictionary {
    func someMethod() {
        for (key, value) in self {
            if let valueString = value as? String {
                println("  \(key) = \(valueString)")
            } else {
                println("  \(key) = \(value) cannot be cast to `String`")
            }
        }
    }
}

So consider the following code:

let dictionary: [String: AnyObject?] = ["foo": "bar"]
dictionary.someMethod()

And it curiously reports

foo = Optional(bar) cannot be cast to `String`

I can write a non-extension method that handles dictionary parameters with optional values, but don't see how to do it as an extension of Dictionary.

like image 992
Rob Avatar asked Jan 03 '15 16:01

Rob


1 Answers

You could do this with reflection. Doesn't require much more code than you already have:

extension Dictionary
{
    func someMethod()
    {
        for (key, value) in self
        {
            var valueRef = _reflect(value)

            while valueRef.disposition == .Optional && valueRef.count > 0 && valueRef[0].0 == "Some"
            {
                valueRef = valueRef[0].1
            }

            if let valueString: String = valueRef.value as? String
            {
                print("  \(key) = \(valueString)")
            }
            else
            {
                print("  \(key) = \(value) cannot be cast to `String`")
            }
        }
    }
}

let dictionary: [String : AnyObject?] = ["foo" : "bar"]
dictionary.someMethod()

Returns

foo = bar

let dictionary: [String : AnyObject?] = ["foo" : nil]
dictionary.someMethod()

Returns

foo = nil cannot be cast to `String`

let dictionary: [String : AnyObject?] = ["foo" : UIViewController()]
dictionary.someMethod()

Returns

foo = Optional(<UIViewController: 0x7fee7e819870>) cannot be cast to `String`
like image 97
Ben Kane Avatar answered Oct 06 '22 02:10

Ben Kane