Skip to content

Instantly share code, notes, and snippets.

@iSame7
Forked from IanKeen/DictionaryConvertable.swift
Created August 24, 2016 01:39
Show Gist options
  • Select an option

  • Save iSame7/cba07517fa038e8710fb72e5044e4088 to your computer and use it in GitHub Desktop.

Select an option

Save iSame7/cba07517fa038e8710fb72e5044e4088 to your computer and use it in GitHub Desktop.
Protocol to handle conversions between Models (class or struct based) and Dictionaries. Model to Dictionary has a default implementation provided for simple 1:1 Models
protocol DictionaryConvertable {
static func fromDictionary(dictionary: [String: AnyObject]) throws -> Self
func toDictionary() -> [String: AnyObject]
}
protocol DictionaryValueType {
func dictionaryValue() -> AnyObject?
}
extension Optional: DictionaryValueType {
func dictionaryValue() -> AnyObject? {
switch self {
case .Some(let value):
if let value = value as? DictionaryValueType {
return value.dictionaryValue()
}
return value as? AnyObject
case .None: return nil
}
}
}
extension DictionaryConvertable {
func toDictionary() -> [String: AnyObject] {
return convertToDictionary(self)
}
}
func convertToDictionary<T: DictionaryConvertable>(convertable: T) -> [String: AnyObject] {
return Mirror(reflecting: convertable).toDictionary()
}
extension Mirror {
private func toDictionary() -> [String: AnyObject] {
let output = self.children.reduce([:]) { (result: [String: AnyObject], child) in
guard let key = child.label else { return result }
let childMirror = Mirror(reflecting: child.value)
if let style = childMirror.displayStyle where style == .Collection {
let converted: [AnyObject] = childMirror.children
.filter {
$0.value is DictionaryConvertable ||
$0.value is DictionaryValueType ||
$0.value is AnyObject
}
.flatMap { collectionChild in
if let convertable = collectionChild.value as? DictionaryConvertable {
return convertable.toDictionary()
} else if let value = collectionChild.value as? DictionaryValueType {
return value.dictionaryValue()
} else {
return collectionChild.value as? AnyObject
}
}
return result + [key: converted]
} else {
if let value = child.value as? DictionaryConvertable {
return result + [key: value.toDictionary()]
} else if let dictionaryValue = child.value as? DictionaryValueType, let value = dictionaryValue.dictionaryValue() {
return result + [key: value]
} else if let value = child.value as? AnyObject {
return result + [key: value]
}
}
return result
}
if let superClassMirror = self.superclassMirror() {
return output + superClassMirror.toDictionary()
}
return output
}
}
func + <K>(left: [K: AnyObject], right: [K: AnyObject]) -> [K: AnyObject] {
var result = [K: AnyObject]()
[left, right].forEach { dict in
dict.forEach { key, value in
if
let currentValue = result[key] as? [K: AnyObject],
let incomingValue = value as? [K: AnyObject],
let newValue = currentValue + incomingValue as? AnyObject {
result[key] = newValue
} else {
result[key] = value
}
}
}
return result
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment