Czy Swift wspiera refleksję? np. czy istnieje coś takiego jak valueForKeyPath:
i setValue:forKeyPath:
dla obiektów Swift?
Właściwie to ma w ogóle dynamiczny system typów, coś w rodzaju obj.class
Objective-C?
Czy Swift wspiera refleksję? np. czy istnieje coś takiego jak valueForKeyPath:
i setValue:forKeyPath:
dla obiektów Swift?
Właściwie to ma w ogóle dynamiczny system typów, coś w rodzaju obj.class
Objective-C?
Odpowiedzi:
Wygląda na to, że jest początek wsparcia dla refleksji:
class Fruit {
var name="Apple"
}
reflect(Fruit()).count // 1
reflect(Fruit())[0].0 // "name"
reflect(Fruit())[0].1.summary // "Apple"
Z istoty mchambers, tutaj: https://gist.github.com/mchambers/fb9da554898dae3e54f2
Mirror
faktycznie cytuje to słowo IDE
kilka razy.
_stdlib_getTypeName
możesz pomóc.
Jeśli klasa się rozszerza NSObject
, wtedy cała introspekcja i dynamizm Objective-C działają. To zawiera:
Jedną z wad tej funkcji jest obsługa opcjonalnych typów wartości języka Swift. Na przykład właściwości Int mogą być wyliczane i modyfikowane, ale Int? właściwości nie mogą. Typy opcjonalne można wyliczyć częściowo za pomocą refleksu / MirrorType, ale nadal nie są one modyfikowane.
Jeśli klasa się nie rozszerza NSObject
, działa tylko nowe, bardzo ograniczone (i w toku?) Odbicie (patrz odbicie / MirrorType), które dodaje ograniczoną możliwość zadawania instancji pytania o jej klasę i właściwości, ale nie ma żadnych dodatkowych funkcji powyżej .
Jeśli nie rozszerzasz NSObject lub używasz dyrektywy „@objc”, Swift domyślnie korzysta z wysyłek statycznych i vtable. Jest to jednak szybsze, jednak w przypadku braku maszyny wirtualnej nie pozwala na przechwycenie metody w czasie wykonywania. To przechwycenie jest podstawową częścią Cocoa i jest wymagane dla następujących typów funkcji:
Dlatego zaleca się stosowanie klas w aplikacjach Cocoa / CocoaTouch zaimplementowanych w Swift:
Podsumowanie:
Dane referencyjne: obciążenie związane z wykonywaniem wywołań metod:
(rzeczywista wydajność zależy od sprzętu, ale wskaźniki pozostaną podobne).
Ponadto atrybut dynamiczny pozwala nam wyraźnie poinstruować Swift, że metoda powinna używać dynamicznego wysyłania, a zatem będzie obsługiwać przechwytywanie.
public dynamic func foobar() -> AnyObject {
}
Dokumentacja mówi o dynamicznym systemie typów, głównie o
Type
i dynamicType
Zobacz Typ metatypu (w odwołaniu do języka)
Przykład:
var clazz = TestObject.self
var instance: TestObject = clazz()
var type = instance.dynamicType
println("Type: \(type)") //Unfortunately this prints only "Type: Metatype"
Teraz zakładając, że się TestObject
rozciągaNSObject
var clazz: NSObject.Type = TestObject.self
var instance : NSObject = clazz()
if let testObject = instance as? TestObject {
println("yes!") //prints "yes!"
}
Obecnie nie ma wdrożonej refleksji.
EDYCJA: Najwyraźniej się myliłem, zobacz odpowiedź Stevexa. Istnieje pewne proste odbicie tylko do odczytu dla wbudowanych właściwości, prawdopodobnie w celu umożliwienia środowiskom IDE inspekcji zawartości obiektu.
Wygląda na to, że interfejs API Swift refleksji nie jest obecnie priorytetem dla Apple. Ale oprócz odpowiedzi @stevex jest jeszcze jedna funkcja w bibliotece standardowej, która pomaga.
Od wersji beta 6 _stdlib_getTypeName
pobiera zniekształconą nazwę typu zmiennej. Wklej to do pustego placu zabaw:
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))")
Wynik to:
TypeName0 = NSString
TypeName1 = _TtC13__lldb_expr_014PureSwiftClass
TypeName2 = _TtSi
TypeName3 = _TtSS
Wpis na blogu Ewana Swicka pomaga rozszyfrować te ciągi:
np. _TtSi
oznacza wewnętrzny Int
typ Swift .
Możesz zamiast tego rozważyć użycie metody toString () . Jest publiczny i działa tak samo jak _stdlib_getTypeName () z tą różnicą, że działa również na AnyClass , np. W Playground enter
class MyClass {}
toString(MyClass.self) // evaluates to "__lldb_expr_49.MyClass"
Brak reflect
słowa kluczowego w Swift 5, teraz możesz go użyć
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
deserializacji