Поддерживает ли Swift рефлексию? например, есть ли что-то подобное valueForKeyPath:
и setValue:forKeyPath:
для объектов Swift?
На самом деле, есть ли в нем даже система динамических типов, как obj.class
в Objective-C?
Поддерживает ли Swift рефлексию? например, есть ли что-то подобное valueForKeyPath:
и setValue:forKeyPath:
для объектов Swift?
На самом деле, есть ли в нем даже система динамических типов, как obj.class
в Objective-C?
Ответы:
Похоже, это начало некоторой поддержки отражения:
class Fruit {
var name="Apple"
}
reflect(Fruit()).count // 1
reflect(Fruit())[0].0 // "name"
reflect(Fruit())[0].1.summary // "Apple"
Из mchambers gist здесь: https://gist.github.com/mchambers/fb9da554898dae3e54f2
Mirror
фактически цитирует это слово IDE
несколько раз.
_stdlib_getTypeName
помочь.
Если класс расширяется NSObject
, тогда весь самоанализ и динамизм Objective-C работают. Это включает:
Одним из недостатков этой функции является поддержка дополнительных типов значений Swift. Например, свойства Int можно перечислить и изменить, но Int? свойства не могут. Необязательные типы могут быть частично перечислены с помощью метода Reflection / MirrorType, но не изменены.
Если класс не расширяется NSObject
, то работает только новое, очень ограниченное (и в процессе?) Отражение (см. «Reflection / MirrorType»), которое добавляет ограниченную возможность запрашивать экземпляр о его классе и свойствах, но ни одной из дополнительных функций выше .
Если не расширять NSObject или не использовать директиву @objc, Swift по умолчанию использует отправку на основе статических и виртуальных таблиц. Это быстрее, однако при отсутствии виртуальной машины не допускается перехват метода среды выполнения. Этот перехват является фундаментальной частью Какао и требуется для следующих типов функций:
Поэтому рекомендуется, чтобы clases в приложениях Cocoa / CocoaTouch, реализованных с помощью Swift:
Резюме:
Справочные данные: накладные расходы на выполнение для вызовов методов:
(фактическая производительность зависит от оборудования, но соотношения останутся аналогичными).
Кроме того, атрибут dynamic позволяет нам явно указать Swift, что метод должен использовать динамическую отправку и, следовательно, будет поддерживать перехват.
public dynamic func foobar() -> AnyObject {
}
В документации говорится о системе динамических типов, в основном о
Type
и dynamicType
См. Тип метатипа (в справочнике по языку)
Пример:
var clazz = TestObject.self
var instance: TestObject = clazz()
var type = instance.dynamicType
println("Type: \(type)") //Unfortunately this prints only "Type: Metatype"
Предполагая, что TestObject
расширяетсяNSObject
var clazz: NSObject.Type = TestObject.self
var instance : NSObject = clazz()
if let testObject = instance as? TestObject {
println("yes!") //prints "yes!"
}
В настоящее время рефлексия не реализована.
РЕДАКТИРОВАТЬ: Я был явно неправ, см. Ответ Стивекса. Существует простое отражение только для чтения для встроенных свойств, возможно, чтобы позволить IDE проверять содержимое объекта.
Кажется, что API отражения Swift не является приоритетом для Apple на данный момент. Но помимо ответа @stevex в стандартной библиотеке есть еще одна функция, которая помогает.
Начиная с бета 6, _stdlib_getTypeName
получает искаженное имя типа переменной. Вставьте это в пустую игровую площадку:
import Foundation
class PureSwiftClass {
}
var myvar0 = NSString() // Objective-C class
var myvar1 = PureSwiftClass()
var myvar2 = 42
var myvar3 = "Hans"
println( "TypeName0 = \(_stdlib_getTypeName(myvar0))")
println( "TypeName1 = \(_stdlib_getTypeName(myvar1))")
println( "TypeName2 = \(_stdlib_getTypeName(myvar2))")
println( "TypeName3 = \(_stdlib_getTypeName(myvar3))")
Результат:
TypeName0 = NSString
TypeName1 = _TtC13__lldb_expr_014PureSwiftClass
TypeName2 = _TtSi
TypeName3 = _TtSS
Запись в блоге Юэна Свика помогает расшифровать эти строки:
например, _TtSi
обозначает внутренний Int
тип Swift .
У Майка Эша есть отличная запись в блоге, посвященная той же теме .
Вместо этого вы можете рассмотреть возможность использования toString () . Он общедоступен и работает так же, как _stdlib_getTypeName (), с той разницей, что он также работает с AnyClass , например, на игровой площадке введите
class MyClass {}
toString(MyClass.self) // evaluates to "__lldb_expr_49.MyClass"
В reflect
Swift 5 нет ключевого слова, теперь вы можете использовать
struct Person {
var name="name"
var age = 15
}
var me = Person()
var mirror = Mirror(reflecting: me)
for case let (label?, value) in mirror.children {
print (label, value)
}
json
десериализации