Skip to content

Instantly share code, notes, and snippets.

@loganwright
Created July 18, 2015 01:21
Show Gist options
  • Save loganwright/fef555b38c3438565793 to your computer and use it in GitHub Desktop.
Save loganwright/fef555b38c3438565793 to your computer and use it in GitHub Desktop.
Dictionary+KeyPaths
import Foundation
extension Dictionary {
mutating public func setValue(val: AnyObject, forKeyPath keyPath: String) {
var keys = keyPath.componentsSeparatedByString(".")
guard let first = keys.first as? Key else { print("Unable to use string as key on type: \(Key.self)"); return }
keys.removeAtIndex(0)
if keys.isEmpty, let settable = val as? Value {
self[first] = settable
} else {
let rejoined = ".".join(keys)
var subdict: [NSObject : AnyObject] = [:]
if let sub = self[first] as? [NSObject : AnyObject] {
subdict = sub
}
subdict.setValue(val, forKeyPath: rejoined)
if let settable = subdict as? Value {
self[first] = settable
} else {
print("Unable to set value: \(subdict) to dictionary of type: \(self.dynamicType)")
}
}
}
public func valueForKeyPath<T>(keyPath: String) -> T? {
var keys = keyPath.componentsSeparatedByString(".")
guard let first = keys.first as? Key else { print("Unable to use string as key on type: \(Key.self)"); return nil }
guard let value = self[first] as? AnyObject else { return nil }
keys.removeAtIndex(0)
if !keys.isEmpty, let subDict = value as? [NSObject : AnyObject] {
let rejoined = ".".join(keys)
return subDict.valueForKeyPath(rejoined)
}
return value as? T
}
}
@juwencheng
Copy link

Swift 4

extension Dictionary {
    mutating public func setValue(value: Any, forKeyPath keyPath: String) {
        var keys = keyPath.components(separatedBy: ".")
        guard let first = keys.first as? Key else { print("Unable to use string as key on type: \(Key.self)"); return }
        keys.remove(at: 0)
        if keys.isEmpty, let settable = value as? Value {
            self[first] = settable
        } else {
            let rejoined = keys.joined(separator: ".")
            var subdict: [NSObject : AnyObject] = [:]
            if let sub = self[first] as? [NSObject : AnyObject] {
                subdict = sub
            }
            subdict.setValue(value: value, forKeyPath: rejoined)
            if let settable = subdict as? Value {
                self[first] = settable
            } else {
                print("Unable to set value: \(subdict) to dictionary of type: \(type(of: self))")
            }
        }
        
    }
    
    public func valueForKeyPath<T>(keyPath: String) -> T? {
        var keys = keyPath.components(separatedBy: ".")
        guard let first = keys.first as? Key else { print("Unable to use string as key on type: \(Key.self)"); return nil }
        guard let value = self[first] else { return nil }
        keys.remove(at: 0)
        if !keys.isEmpty, let subDict = value as? [NSObject : AnyObject] {
            let rejoined = keys.joined(separator: ".")
            
            return subDict.valueForKeyPath(keyPath: rejoined)
        }
        return value as? T
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment