Swift yansımayı destekliyor mu?


113

Swift yansımayı destekliyor mu? örneğin gibi orada bir şeydir valueForKeyPath:ve setValue:forKeyPath:Swift nesneler için?

Aslında obj.classObjective-C'de olduğu gibi dinamik bir tip sistemi var mı?


1
Swift'de yansıma için yardımcı bir sınıf oluşturdum. Bunu şu adreste bulabilirsiniz: github.com/evermeer/EVReflection
Edwin Vermeer

2
Swift 2.0'daki yansımayı kaldırdılar. Öznitelikleri ve değerleri bu şekilde
sıralıyorum

Yanıtlar:


85

Görünüşe göre bazı yansıma desteğinin başlangıcı var:

class Fruit {
    var name="Apple"
}

reflect(Fruit()).count         // 1
reflect(Fruit())[0].0          // "name"
reflect(Fruit())[0].1.summary  // "Apple"

Mchambers gist'ten buraya: https://gist.github.com/mchambers/fb9da554898dae3e54f2


5
Ben bunu gerçek bir yansıma olarak görmezdim. Birincisi, salt okunur. Bana öyle geliyor ki, Xcode'da hata ayıklamayı etkinleştirmek için sadece bir hack. Protokol Mirroraslında kelimeyi IDEbirkaç kez alıntılar .
Sulthan

7
Ve sadece mülkler için çalışır. Yöntem yansıması yok.
Sulthan

11
Özetin yazarı kontrol ediyor. Bunu WWDC'deki Swift laboratuarında yazdım, geri kalanını paylaşacağımı düşündüm. Herkesin anladığı gibi, konuştuğum mühendisler, Playground'u desteklemek için yansıtma () işlevinin var olduğunu doğruladılar. Ama yine de onunla biraz eğlenebilirsiniz :) burada onu kullanarak küçük bir model serileştiriciyi hackledim. Oyun Alanına
Marc Chambers

1
Nasıl yardımcı olabileceğini öğrenmek için stackoverflow.com/a/25345461/292145 yanıtına bir göz atın _stdlib_getTypeName.
Klaas

1
İşte temel sınıfları ve opsiyonelleri (türleri değil) yansıtacak ve NSCoding ve sözlüğe ayrıştırma desteği olan bir sınıf: github.com/evermeer/EVCloudKit Dao/blob/master/AppMessage/…
Edwin Vermeer

44

Bir sınıf genişlerse NSObject, Objective-C'nin tüm iç gözlemi ve dinamizmi çalışır. Bu içerir:

  • Bir sınıfa yöntemleri ve özellikleri hakkında soru sorma ve yöntemleri çağırma veya özellikleri ayarlama yeteneği.
  • Yöntem uygulamalarını değiş tokuş etme yeteneği. (tüm örneklere işlevsellik ekleyin).
  • Anında yeni bir alt sınıf oluşturma ve atama yeteneği. (belirli bir örneğe işlevsellik ekleyin)

Bu işlevin bir dezavantajı, Swift isteğe bağlı değer türlerinin desteklenmesidir. Örneğin, Int özellikleri numaralandırılabilir ve değiştirilebilir ancak Int? özellikler olamaz. İsteğe bağlı türler, yansıtma / MirrorType kullanılarak kısmen numaralandırılabilir, ancak yine de değiştirilemez.

Bir sınıf genişlemezse NSObject, yalnızca yeni, çok sınırlı (ve devam etmekte olan?) Yansıtma çalışır (bkz. Yansıtma / MirrorType), bu da bir örneğe sınıfı ve özellikleri hakkında soru sorma konusunda sınırlı bir yetenek ekler, ancak yukarıdaki ek özelliklerin hiçbiri .

NSObject'i genişletmediğinde veya '@objc' direktifini kullanmadığında, Swift varsayılan olarak statik ve vtable tabanlı gönderime geçer. Bu daha hızlıdır, ancak bir sanal makinenin yokluğunda çalışma zamanı yönteminin kesilmesine izin vermez. Bu müdahale, Cocoa'nın temel bir parçasıdır ve aşağıdaki özellik türleri için gereklidir:

  • Cocoa'nın zarif emlak gözlemcileri. (Mülkiyet gözlemcileri doğrudan Swift dilinde pişirilir).
  • Günlüğe kaydetme, işlem yönetimi (yani Unsur Odaklı Programlama) gibi girişimsel olmayan kesişen endişeleri uygulamak.
  • Proxy'ler, mesaj yönlendirme vb.

Bu nedenle, Swift ile uygulanan Cocoa / CocoaTouch uygulamalarındaki sınıfların:

  • NSObject'ten genişletin. Xcode'daki yeni sınıf iletişim kutusu bu yönde yönlendirilir.
  • Dinamik bir gönderimin ek yükünün performans sorunlarına yol açtığı durumlarda, statik dağıtım kullanılabilir - örneğin, çok küçük gövdeli yöntemlere çağrılarla sıkı döngülerde.

Özet:

  • Swift, hızlı statik / vtable gönderimi ve sınırlı yansıma ile C ++ gibi davranabilir. Bu, onu daha düşük seviyeli veya yoğun performans gerektiren uygulamalar için uygun hale getirir, ancak karmaşıklık, öğrenme eğrisi veya C ++ ile ilişkili hata riski olmadan
  • Swift derlenmiş bir dil olsa da, yöntem çağırmanın mesajlaşma stili Ruby ve Python gibi modern dillerde bulunan iç gözlemi ve dinamizmi, tıpkı Objective-C gibi, ancak Objective-C'nin eski sözdizimi olmadan ekler.

Referans verileri: Yöntem çağrıları için yürütme ek yükü:

  • statik: <1.1ns
  • vtable: ~ 1.1ns
  • dinamik: ~ 4.9ns

(gerçek performans donanıma bağlıdır, ancak oranlar benzer kalacaktır).

Ayrıca, dinamik öznitelik, Swift'e bir yöntemin dinamik gönderimi kullanması gerektiğini açıkça bildirmemize olanak tanır ve bu nedenle durdurmayı destekleyecektir.

public dynamic func foobar() -> AnyObject {
}

2
Objective-C tekniklerini kullansanız bile, isteğe bağlı Swift türleri için çalışmıyor gibi görünüyor. Bir hileyi kaçırmadığım sürece bu sınırlamayı cevapta belirtmenizi öneririm.
whitneyland

8

Dokümantasyon, dinamik tip sistemden bahsediyor, özellikle

Type ve dynamicType

Bkz (Dil Başvurusu) Metatype Tipi

Misal:

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

var type = instance.dynamicType

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

Şimdi varsayarak TestObjectuzanırNSObject

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

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

Şu anda herhangi bir yansıma uygulanmamaktadır.

DÜZENLEME: Görünüşe göre yanılmışım, stevex'in cevabına bakın. Muhtemelen IDE'lerin nesne içeriklerini incelemesine izin vermek için yerleşik özellikler için bazı basit salt okunur yansıma vardır.


6

Görünüşe göre Swift yansıtma API'si şu anda Apple için yüksek bir öncelik değil. Ancak @stevex cevabının yanı sıra , standart kitaplıkta yardımcı olan başka bir işlev daha var.

Beta 6 _stdlib_getTypeNameitibariyle bir değişkenin karıştırılmış tür adını alır. Bunu boş bir oyun alanına yapıştırın:

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

Çıktı:

TypeName0 = NSString
TypeName1 = _TtC13__lldb_expr_014PureSwiftClass
TypeName2 = _TtSi
TypeName3 = _TtSS

Ewan Swick'in blog yazısı şu dizeleri deşifre etmeye yardımcı olur:

örneğin _TtSi, Swift'in dahili Inttürünü ifade eder.

Mike Ash'in aynı konuyu kapsayan harika bir blog girişi var .


@aleclarson Evet, bu da oldukça kullanışlı.
Klaas

1
bunlar özel API değil mi? Apple, kullanılırsa uygulamayı onaylayacak mı?
Eduardo Costa

@EduardoCosta evet, kesinlikle. Özeldirler. Bunları yalnızca hata ayıklama yapıları için kullanıyorum.
Klaas

İşte Ewan Swick'in blog makalesine güncellenmiş bir bağlantı: eswick.com/2014/06/08/Inside-Swift
RenniePet

5

Bunun yerine toString () kullanmayı düşünebilirsiniz . Herkese açıktır ve _stdlib_getTypeName () ile aynı şekilde çalışır, farkı, aynı zamanda AnyClass üzerinde de çalışır , örneğin Playground enter'da

class MyClass {}

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

1

reflectSwift 5'te anahtar kelime yok , şimdi kullanabilirsiniz

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

Neden buna olumlu oy verilmedi? Bu v yararlıdır. Ben bunu uygulamak için gidiyorum jsonseri kaldırma
javadba
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.