Поддерживает ли Swift отражение?

Поддерживает ли Swift отражение? например есть ли что-то вроде valueForKeyPath: и setValue:forKeyPath: для объектов Swift?

На самом деле у него даже есть система динамического типа, что-то вроде obj.class в Objective-C?

Ответ 1

Похоже, что начало некоторой поддержки отражения:

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

Ответ 2

Если класс расширяет NSObject, то работает все интроспекция и динамизм Objective-C. Это включает в себя:

  • Возможность спросить класс о его методах и свойствах, а также вызвать методы или установить свойства.
  • Возможность обмена реализациями метода. (добавьте функциональность ко всем экземплярам).
  • Возможность генерировать и назначать новый подкласс на лету. (добавить функциональность к данному экземпляру)

Одним из недостатков этой функции является поддержка дополнительных типов значений Swift. Например, свойства Int могут быть перечислены и изменены, но Int? свойства не могут. Необязательные типы могут быть перечислены частично с использованием mirror/MirrorType, но все еще не изменены.

Если класс не расширяет NSObject, то работает только новое, очень ограниченное (и в процессе?) отражение (см. отражение /MirrorType ), что добавляет ограниченную способность запрашивать экземпляр о его классе и свойствах, но ни одна из дополнительных функций выше.

Если не расширять NSObject или использовать директиву "@objc", по умолчанию Swift используется для отправки по статической и виртуальной таблицам. Однако это происходит быстрее, но при отсутствии виртуальной машины не разрешается перехват метода времени исполнения. Этот перехват является фундаментальной частью Cocoa и требуется для следующих типов функций:

  • Cocoa элегантные наблюдатели свойств. (Собственные наблюдатели запекаются прямо на языке Swift).
  • Неинвазивно применяя сквозные проблемы, такие как ведение журнала, управление транзакциями (например, ориентированное на аспектное программирование).
  • Прокси, пересылка сообщений и т.д.

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

  • Выполнить из NSObject. Диалог нового класса в Xcode направляется в этом направлении.
  • В тех случаях, когда накладные расходы на динамическую отправку приводят к проблемам с производительностью, можно использовать статическую отправку - например, в узких петлях с вызовами методов с очень маленькими телами.

Резюме:

  • Swift может вести себя как С++, с быстрой отправкой static/vtable и ограниченным отражением. Это делает его подходящим для приложений с более низким уровнем производительности или высокой производительности, но без сложности, кривой обучения или риска ошибки, связанной с С++
  • В то время как Swift - это скомпилированный язык, стиль обмена сообщениями вызова метода добавляет интроспекцию и динамизм, найденные на современных языках, таких как Ruby и Python, как и Objective-C, но без Objective-C устаревшего синтаксиса.

Справочные данные: служебные данные выполнения для вызовов методов:

  • static: < 1.1нс
  • vtable: ~ 1.1ns
  • dynamic: ~ 4.9ns

(фактическая производительность зависит от аппаратного обеспечения, но коэффициенты останутся похожими).

Кроме того, динамический атрибут позволяет нам явно проинструктировать Swift о том, что метод должен использовать динамическую отправку и, следовательно, поддерживать перехват.

public dynamic func foobar() -> AnyObject {
}

Ответ 3

Документация говорит о системе динамического типа, в основном о

Type и dynamicType

См. Тип метатипа (в справочнике по языку)

Пример:

var clazz = TestObject.self
var instance: TestObject = clazz()

var type = instance.dynamicType

println("Type: \(type)") //Unfortunately this prints only "Type: Metatype"

Теперь предположим, что TestObject extends NSObject

var clazz: NSObject.Type = TestObject.self
var instance : NSObject = clazz()

if let testObject = instance as? TestObject {
    println("yes!") //prints "yes!"
}

В настоящее время не реализовано отражение.

РЕДАКТИРОВАТЬ: Я, по-видимому, ошибался, см. stevex ответ. Существует некоторое простое отображение readonly для построения свойств, возможно, чтобы IDE могли проверять содержимое объекта.

Ответ 4

Похоже, что API Swift для отражения в настоящее время не является для Apple приоритетом. Но помимо @stevex answer есть другая функция в стандартной библиотеке, которая помогает.

Начиная с бета-версии 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

Запись в блоге Ewan Swick помогает расшифровать эти строки:

например. _TtSi обозначает внутренний тип Swift Int.

У Майка Эша отличная запись в блоге, посвященная той же теме.

Ответ 5

Вместо этого вы можете использовать toString(). Он является общедоступным и работает так же, как _stdlib_getTypeName() с той разницей, что он также работает на AnyClass, например. на игровой площадке введите

class MyClass {}

toString(MyClass.self) // evaluates to "__lldb_expr_49.MyClass"