2016-03-16 9 views
6

Ich habe mehrere rasche Klassen, wie ähnlich aussehen wie folgtSo extrahieren Sie optionale typisierte Werte von "Spiegeln" in Swift?

public class Book { 
    var title: String? 
    var date: NSDate? 
} 

Da es mehrere verschiedene Klassen, wo ich die Eigenschaften zugreifen müssen, ich Reflexion bin mit durch die Eigenschaften der Klasse auszuführen:

let myBook = Book() 
myBook.title = "Hello" 
myBook.date = NSDate() 

let mirror = Mirror(reflecting: myBook) 
var propsArr = [(key: String?, value: Any)]() 
let mirrorChildrenCollection = AnyRandomAccessCollection(mirror.children)! 
if mirrorChildrenCollection.count > 0 { 
    propsArr += mirrorChildrenCollection 
} 

//iterate through properties 
for case let (label?, value) in propsArr { 
    print (label, value) 

    if let val = value as? NSDate { 
    var extractedDate = val 
    print(extractedDate) 
    } 
    else if let val = value as? String { 
    var extractedTitle = val 
    print (extractedTitle) 
    } 
} 

Aber ich habe ein Problem, dass die Child-Objekte nicht extrahiert werden, da sie von Typ Any und intern optional Klassen sind und daher nicht in meine Fälle fallen. Wenn ich den Titel von String ändere? zu String, sie funktionieren, aber ich muss optionale Typen verwenden.

Was kann ich in der obigen Implementierung ändern, um den Datentyp als String zu belassen? und Datum? und noch die Werte aus dem Spiegel extrahieren?

Antwort

4

Es scheint, dass dies in Swift 2.x nicht möglich ist.

Da die Eigenschaften optionals sind, würden Sie jeweils NSDate? und String?, werfen müssen, wie folgt aus:

if let val = value as? NSDate? { 
    // val is Optional<NSDate> 
} 

Leider hat der Compiler dies nicht zulassen, dass (ich bin nicht sicher, warum): // error: cannot downcast from 'protocol<>' to a more optional type 'NSDate?'.

This answer von bubuxu bietet eine clevere Problemumgehung, die funktionieren würde, wenn Sie eine für jede Eigenschaft hätten. Die Eigenschaft displayStyle des Spiegels teilt Ihnen mit, ob es sich um einen optionalen Wert handelt, und Sie können den umbrochenen Wert dann manuell extrahieren. So würde diese Arbeit:

let child = Mirror(reflecting: myBook.date) 
child.displayStyle 
if child.displayStyle == .Optional { 
    if child.children.count == 0 { 
     // .None 
    } else { 
     // .Some 
     let (_, some) = child.children.first! 
     if let val = some as? NSDate { 
      print(val) 
     } 
    } 
} 

Aber das hängt davon ab, für jede Eigenschaft eine Mirror hat, und es scheint, man kann nicht ein Mirror ‚s Kinder durchqueren Mirror s für sie zurückzuholen.