Swift supporta la riflessione? es. c'è qualcosa come valueForKeyPath:
e setValue:forKeyPath:
per gli oggetti Swift?
In realtà ha anche un sistema di tipi dinamico, qualcosa come obj.class
in Objective-C?
Swift supporta la riflessione? es. c'è qualcosa come valueForKeyPath:
e setValue:forKeyPath:
per gli oggetti Swift?
In realtà ha anche un sistema di tipi dinamico, qualcosa come obj.class
in Objective-C?
Risposte:
Sembra che ci sia l'inizio di un supporto di riflessione:
class Fruit {
var name="Apple"
}
reflect(Fruit()).count // 1
reflect(Fruit())[0].0 // "name"
reflect(Fruit())[0].1.summary // "Apple"
Da mchambers gist, qui: https://gist.github.com/mchambers/fb9da554898dae3e54f2
Mirror
cita effettivamente la parola IDE
più volte.
_stdlib_getTypeName
può aiutarti.
Se una classe si estende NSObject
, allora tutta l'introspezione e il dinamismo di Objective-C funzionano. Ciò comprende:
Un difetto di questa funzionalità è il supporto per i tipi di valore facoltativi di Swift. Ad esempio, le proprietà Int possono essere enumerate e modificate ma Int? le proprietà non possono. I tipi opzionali possono essere enumerati parzialmente utilizzando riflettere / MirrorType, ma non ancora modificati.
Se una classe non si estende NSObject
, allora funziona solo la nuova riflessione molto limitata (e in corso?) (Vedi Reflect / MirrorType), che aggiunge una capacità limitata di chiedere a un'istanza la sua classe e le sue proprietà, ma nessuna delle funzionalità aggiuntive sopra .
Quando non si estende NSObject o si utilizza la direttiva "@objc", Swift utilizza per impostazione predefinita l'invio basato su statico e vtable. Questo è più veloce, tuttavia, in assenza di una macchina virtuale non consente l'intercettazione del metodo di runtime. Questa intercettazione è una parte fondamentale di Cocoa ed è necessaria per i seguenti tipi di caratteristiche:
Pertanto si consiglia di classificare nelle applicazioni Cocoa / CocoaTouch implementate con Swift:
Sommario:
Dati di riferimento: overhead di esecuzione per invocazioni di metodi:
(le prestazioni effettive dipendono dall'hardware, ma i rapporti rimarranno simili).
Inoltre, l'attributo dinamico ci consente di indicare esplicitamente a Swift che un metodo deve utilizzare l'invio dinamico e quindi supporterà l'intercettazione.
public dynamic func foobar() -> AnyObject {
}
La documentazione parla di un sistema di tipi dinamico, principalmente di
Type
e dynamicType
Vedi Metatype Type (in Language Reference)
Esempio:
var clazz = TestObject.self
var instance: TestObject = clazz()
var type = instance.dynamicType
println("Type: \(type)") //Unfortunately this prints only "Type: Metatype"
Ora assumendo TestObject
si estendeNSObject
var clazz: NSObject.Type = TestObject.self
var instance : NSObject = clazz()
if let testObject = instance as? TestObject {
println("yes!") //prints "yes!"
}
Attualmente non è stata implementata alcuna riflessione.
EDIT: apparentemente mi sbagliavo, vedi la risposta di Stevex. C'è qualche semplice riflessione di sola lettura per le proprietà incorporate, probabilmente per consentire agli IDE di ispezionare il contenuto degli oggetti.
Sembra che un'API di riflessione Swift non sia una priorità assoluta per Apple al momento. Ma oltre alla risposta di @stevex c'è un'altra funzione nella libreria standard che aiuta.
A partire dalla beta 6 _stdlib_getTypeName
ottiene il nome del tipo alterato di una variabile. Incolla questo in un playground vuoto:
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))")
L'output è:
TypeName0 = NSString
TypeName1 = _TtC13__lldb_expr_014PureSwiftClass
TypeName2 = _TtSi
TypeName3 = _TtSS
La voce del blog di Ewan Swick aiuta a decifrare queste stringhe:
ad esempio _TtSi
sta per Int
tipo interno di Swift .
Mike Ash ha un ottimo post sul blog che copre lo stesso argomento .
Potresti prendere in considerazione l'utilizzo di toString () invece. È pubblico e funziona esattamente come _stdlib_getTypeName () con la differenza che funziona anche su AnyClass , ad esempio in un Playground entra
class MyClass {}
toString(MyClass.self) // evaluates to "__lldb_expr_49.MyClass"
Nessuna reflect
parola chiave in Swift 5, ora puoi usare
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
deserializzazione