2016-03-16 3 views
6

У меня есть несколько быстрых классов, которые внешне похожи, как следующийКак извлечь необязательные типизированные значения из детей Mirror в Swift?

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

Поскольку существует несколько различных классов, где мне нужно, чтобы получить доступ к свойствам, я использую отражение пробежать свойства класса:

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) 
    } 
} 

Но у меня есть проблема, что объекты Child не извлекаются, поскольку они относятся к типу Any и внутренне необязательным классам и, таким образом, не попадают в мои случаи. Если я изменю название из String? для String они работают, но мне нужно использовать необязательные типы.

Что я могу изменить в приведенной выше реализации, чтобы оставить тип данных как String? и дата? и все еще извлекать значения из зеркала?

ответ

4

Кажется, это невозможно в Swift 2.x.

Поскольку свойства OPTIONALS, вы должны бросить в NSDate? и String?, соответственно, как это:

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

К сожалению, компилятор не позволяет этого (я не знаю, почему): // error: cannot downcast from 'protocol<>' to a more optional type 'NSDate?'.

This answer от bubuxu обеспечивает умное обходное решение, которое будет работать, если у вас есть Mirror для каждой собственности. Свойство mirror displayStyle указывает вам, является ли оно дополнительным, и вы можете извлечь из него завернутое значение вручную. Так что это будет работать:

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) 
     } 
    } 
} 

Но это зависит от наличия Mirror для каждого свойства, и, кажется, вы не можете пройти детям Mirror «s, чтобы получить Mirror с для них.