2014-06-05 7 views
12

Haben Swift-Klassen so etwas wie ein ISA-Zeiger, der neu zugeordnet werden kann?Swift isa Zeiger-Zuordnung oder andere unterstützte Methode Swizzling

Wir haben gesehen, dass Swift uses a more static method dispatch als objective-C, die (sofern nicht eine Klassenherausweise von Foundation/NSObject) den Stil des Swizzling auf der Grundlage von Remapping-Methodenimplementierungen zur Laufzeit verhindert.

Ich frage mich, wie wir Methoden abfangen-basierte dynamische Funktionen wie Beobachter Muster, Benachrichtigungen usw. implementieren? Derzeit wird all dies von der Objective-C-Ebene bereitgestellt und kann problemlos in Swift integriert werden. Aber wenn wir diese Features in einem eigenen Framework (oder App) bereitstellen wollen, müssen wir sie dann in Objective-C implementieren? Ich würde annehmen, dass es einen Weg gibt, es "nativ" zu machen.

Eine andere Art von swizzling, die für objective-C üblich ist, besteht darin, den isa-Zeiger neu zuzuordnen, um eine Unterklasse im laufenden Betrieb zu erzeugen. Wird diese Art Swizzling in Swift unterstützt? Wenn nicht was ist die unterstützte Art des Abfangens beliebiger Methodenaufrufe?

Edit:Als @jatoben weist darauf hin, wie von arm64 isa-Remapping muss direkt durch den Aufruf object_setClass() und nicht durch den Zugriff auf den Wert erfolgen. Dies wird immer noch als "isa Zeiger swizzling"

+0

Es ist nicht sicher, auf isa direkt in Obj-C zuzugreifen, entweder: http://sealiesoftware.com/blog/archive/2013/09/24/objc_explain_Non-pointer_isa.html – jatoben

Antwort

10

Es sieht aus wie beide Methoden austauschen und die isa Zeiger-Remapping-Technik funktioniert nur, wenn die Swift-Klasse NSObject als Super-Klasse (entweder direkt oder weiter oben) hat. Es funktioniert derzeit nicht, wenn die Swift-Klasse keine Superklasse oder eine andere Nicht-Foundation-Basisklasse hat.

Der folgende Test zeigt dies:

Klasse: Birdy

class Birdy: NSObject {  
    func sayHello() 
    { 
     println("tweet tweet") 
    }  
} 

Klasse: HodorBirdy

class HodorBirdy: Birdy { 

    override func sayHello() 
    { 
     super.sayHello() 
     println("hodor hodor") 
    } 
} 

Test:

func testExample() {   
    var birdy : Birdy = Birdy() 
    object_setClass(birdy, HodorBirdy.self) 
    birdy.sayHello(); 
} 

Und der Ausgang wurde wie erwartet:

tweet tweet 
hodor hodor 

In diesem Test sowohl die Basisklasse und Unterklasse wurden im Voraus erstellt. Sie können jedoch auch dynamisch mit der Objective-C-Laufzeit erstellt werden, solange die Klasse NSObject als Vorgänger hat.

Wenn eine Swift-Klasse nicht von der Objective-C-Grundlage abgeleitet wird, wird der Compiler die statische oder Vtable-basierte Verteilung bevorzugen, daher ist es nicht klar, wie Methode Interception in diesem Fall überhaupt funktioniert!

Wenn die Sprache/der Compiler keine spezifische Erlaubnis dafür gibt, verzichten wir auf Dynamik zugunsten der Leistung. (Interception, die die Grundlage für 'dynamisches' Verhalten ist, kann entweder zur Kompilierzeit oder zur Laufzeit ausgeführt werden. Im Falle des Static- oder Vtable-Dispatchings ohne eine virtuelle Maschine gilt nur die Kompilierzeit).

+0

Related: Ist es (im Kontext einer Cocoa/CocoaTouch-Anwendung) normal, dass eine Swift-Klasse keinen Cocoa/NSObject-Vorgänger hat? http://stackoverflow.com/q/24057525/404201 –

2

Ich kann nicht Ihre Frage zu swift "isa" entspricht, aber ich denke, ich weiß einen Teil der Antwort auf Ihre zugrunde liegende Frage.

Eigenschafts-Beobachter scheinen die eingebauten Mittel für das Beobachter-Muster zu sein. Anstelle der Laufzeit-Erkennung von "type" (RTTI, what-have-you) ist es explizit eingewoben.

'Von der Swift Programming Language' Seite 345:

Eigentum Beobachter beobachten und Wert auf Änderungen in einer Immobilie reagieren. Eigenschaftsbeobachter werden jedes Mal aufgerufen, wenn der Wert einer Eigenschaft festgelegt ist, auch wenn der neue Wert dem aktuellen Wert der Eigenschaft entspricht.

Sie können Eigenschaftsbeobachter zu allen gespeicherten Eigenschaften hinzufügen, die Sie definieren, , abgesehen von Lazy Stored Properties. Sie können auch Eigenschaftsbeobachter zu jeder geerbten Eigenschaft (ob gespeichert oder berechnet) hinzufügen, indem Sie die Eigenschaft in eine Unterklasse überschreiben.

Sie haben die Möglichkeit zu definieren, eine oder beide dieser Beobachter auf einer Eigenschaft:

  • willSet heißt, kurz bevor der Wert gespeichert.
  • didSet wird unmittelbar nach dem Speichern des neuen Werts aufgerufen.

Ich bin nicht sicher, wie das alles funktionieren wird, aber ich bin gespannt.

Sich auf die Laufzeit-Typentdeckung zu verlassen, scheint auch der starken statischen Orthodoxie zuwiderzulaufen.

+1

So Eigentum Beobachter sind direkt in gebacken. Nützlich (und nützlich zu wissen). Aber es gibt noch viel mehr nützliche Dinge, die mit dem Abfangmuster zu tun haben. . Mal sehen, ob wir auch eine direkte Antwort geben können. –

+0

Ich erwarte auch, dass Haskell-Anhänger erklären, dass richtig geschriebene Schließungen der richtige Weg sind. Während ich hoffe, explizite Unterstützung für Nebenläufigkeit, wie Kanäle und Goroutines zu entdecken. wenn nur. –

+0

Eine der gültigen Anwendungen der Methodenüberwachung ist die Fähigkeit, "übergreifende Anforderungen" gemäß dem aspect-orientierten Programmierparadigma zu modularisieren. . ObjC-Fans waren begeistert von der Möglichkeit, dies zur Laufzeit zu tun, anstatt ein Kompilierzeit-Tool zu verwenden. Tatsächlich gab es für ObjC keinen formellen AOP-Rahmen, da die "Rohmaterialien" für die Laufzeitüberwachung gut genug waren, um durchzukommen. –