Was sind die Gefahren von Method Swizzling in Objective-C?

235

Ich habe Leute sagen hören, dass Methoden-Swizzling eine gefährliche Praxis ist. Sogar der Name Swizzling deutet darauf hin, dass es sich um einen Betrüger handelt.

Methode Swizzling ändert das Mapping so, dass der Aufruf von Selektor A tatsächlich die Implementierung B aufruft. Eine Verwendung davon besteht darin, das Verhalten von Closed-Source-Klassen zu erweitern.

Können wir die Risiken formalisieren, damit jeder, der sich für die Verwendung von Swizzling entscheidet, eine fundierte Entscheidung treffen kann, ob es sich für das, was er versucht, lohnt?

Z.B

  • Namenskollisionen : Wenn die Klasse später ihre Funktionalität um den von Ihnen hinzugefügten Methodennamen erweitert, führt dies zu einer Vielzahl von Problemen. Reduzieren Sie das Risiko, indem Sie Swizzled-Methoden sinnvoll benennen.
Robert
quelle
Es ist schon nicht sehr gut, etwas anderes von Code zu bekommen, den Sie gelesen haben
Martin Babacaev
Dies klingt nach einer unreinen Methode, um das zu tun, was Python-Dekorateure sehr sauber machen
Claudiu

Antworten:

439

Ich denke, dies ist eine wirklich großartige Frage, und es ist eine Schande, dass die meisten Antworten das Problem umgangen haben und einfach gesagt haben, dass sie kein Swizzling verwenden sollen, anstatt die eigentliche Frage anzugehen.

Mit der Methode Brutzeln ist wie mit scharfen Messern in der Küche. Einige Menschen haben Angst vor scharfen Messern, weil sie denken, dass sie sich schlecht schneiden werden, aber die Wahrheit ist, dass scharfe Messer sicherer sind .

Das Methoden-Swizzling kann verwendet werden, um besseren, effizienteren und wartbareren Code zu schreiben. Es kann auch missbraucht werden und zu schrecklichen Fehlern führen.

Hintergrund

Wie bei allen Entwurfsmustern können wir fundiertere Entscheidungen darüber treffen, ob wir das Muster verwenden oder nicht, wenn wir uns der Konsequenzen des Musters voll bewusst sind. Singletons sind ein gutes Beispiel für etwas, das ziemlich kontrovers ist, und das aus gutem Grund - sie sind wirklich schwer richtig zu implementieren. Viele Menschen entscheiden sich jedoch immer noch für Singletons. Gleiches gilt für das Swizzling. Sie sollten sich eine eigene Meinung bilden, wenn Sie sowohl das Gute als auch das Schlechte vollständig verstanden haben.

Diskussion

Hier sind einige der Fallstricke des Methoden-Swizzling:

  • Methoden-Swizzling ist nicht atomar
  • Ändert das Verhalten von nicht im Besitz befindlichem Code
  • Mögliche Namenskonflikte
  • Durch Swizzling werden die Argumente der Methode geändert
  • Die Reihenfolge der Swizzles ist wichtig
  • Schwer zu verstehen (sieht rekursiv aus)
  • Schwer zu debuggen

Diese Punkte sind alle gültig, und wenn wir sie ansprechen, können wir sowohl unser Verständnis des Methoden-Swizzling als auch die Methodik, mit der das Ergebnis erzielt wird, verbessern. Ich werde jeden nach dem anderen nehmen.

Methoden-Swizzling ist nicht atomar

Ich habe noch keine Implementierung von Methoden-Swizzling gesehen, die sicher gleichzeitig verwendet werden kann 1 . Dies ist in 95% der Fälle, in denen Sie das Methoden-Swizzling verwenden möchten, eigentlich kein Problem. Normalerweise möchten Sie einfach die Implementierung einer Methode ersetzen und möchten, dass diese Implementierung für die gesamte Lebensdauer Ihres Programms verwendet wird. Dies bedeutet, dass Sie Ihre Methode einschalten sollten +(void)load. Die loadKlassenmethode wird zu Beginn Ihrer Anwendung seriell ausgeführt. Sie werden keine Probleme mit der Parallelität haben, wenn Sie hier Ihre Swizzling machen. Wenn Sie jedoch einschalten +(void)initialize, könnte dies zu einer Racebedingung in Ihrer Swizzling-Implementierung führen, und die Laufzeit könnte in einem seltsamen Zustand enden.

Ändert das Verhalten von nicht im Besitz befindlichem Code

Dies ist ein Problem mit dem Swizzling, aber es ist der springende Punkt. Das Ziel ist es, diesen Code ändern zu können. Der Grund, warum die Leute darauf hinweisen, ist, dass Sie nicht nur Dinge für die eine Instanz ändern, für die NSButtonSie Dinge ändern möchten, sondern für alle NSButtonInstanzen in Ihrer Anwendung. Aus diesem Grund sollten Sie beim Swizzeln vorsichtig sein, aber Sie müssen es nicht ganz vermeiden.

Stellen Sie sich das so vor ... Wenn Sie eine Methode in einer Klasse überschreiben und die Superklassenmethode nicht aufrufen, können Probleme auftreten. In den meisten Fällen erwartet die Superklasse, dass diese Methode aufgerufen wird (sofern nicht anders dokumentiert). Wenn Sie denselben Gedanken auf das Swizzling anwenden, haben Sie die meisten Probleme behandelt. Rufen Sie immer die ursprüngliche Implementierung auf. Wenn Sie dies nicht tun, ändern Sie wahrscheinlich zu viel, um sicher zu sein.

Mögliche Namenskonflikte

Namenskonflikte sind in ganz Cocoa ein Thema. Wir stellen häufig Klassennamen und Methodennamen in Kategorien voran. Namenskonflikte sind in unserer Sprache leider eine Plage. Im Falle von Swizzling müssen sie es jedoch nicht sein. Wir müssen nur die Art und Weise ändern, wie wir über Methoden denken, die leicht schwanken. Das meiste Swizzling wird so gemacht:

@interface NSView : NSObject
- (void)setFrame:(NSRect)frame;
@end

@implementation NSView (MyViewAdditions)

- (void)my_setFrame:(NSRect)frame {
    // do custom work
    [self my_setFrame:frame];
}

+ (void)load {
    [self swizzle:@selector(setFrame:) with:@selector(my_setFrame:)];
}

@end

Das funktioniert gut, aber was würde passieren, wenn my_setFrame:es woanders definiert würde ? Dieses Problem betrifft nicht nur das Swizzling, aber wir können es trotzdem umgehen. Die Problemumgehung hat den zusätzlichen Vorteil, dass auch andere Fallstricke behoben werden. Folgendes tun wir stattdessen:

@implementation NSView (MyViewAdditions)

static void MySetFrame(id self, SEL _cmd, NSRect frame);
static void (*SetFrameIMP)(id self, SEL _cmd, NSRect frame);

static void MySetFrame(id self, SEL _cmd, NSRect frame) {
    // do custom work
    SetFrameIMP(self, _cmd, frame);
}

+ (void)load {
    [self swizzle:@selector(setFrame:) with:(IMP)MySetFrame store:(IMP *)&SetFrameIMP];
}

@end

Dies ähnelt zwar etwas weniger Objective-C (da es Funktionszeiger verwendet), vermeidet jedoch Namenskonflikte. Im Prinzip macht es genau das Gleiche wie Standard-Swizzling. Dies mag für Leute, die Swizzling verwenden, wie es seit einiger Zeit definiert ist, eine kleine Veränderung sein, aber am Ende denke ich, dass es besser ist. Die Swizzling-Methode ist folgendermaßen definiert:

typedef IMP *IMPPointer;

BOOL class_swizzleMethodAndStore(Class class, SEL original, IMP replacement, IMPPointer store) {
    IMP imp = NULL;
    Method method = class_getInstanceMethod(class, original);
    if (method) {
        const char *type = method_getTypeEncoding(method);
        imp = class_replaceMethod(class, original, replacement, type);
        if (!imp) {
            imp = method_getImplementation(method);
        }
    }
    if (imp && store) { *store = imp; }
    return (imp != NULL);
}

@implementation NSObject (FRRuntimeAdditions)
+ (BOOL)swizzle:(SEL)original with:(IMP)replacement store:(IMPPointer)store {
    return class_swizzleMethodAndStore(self, original, replacement, store);
}
@end

Durch Umbenennen von Methoden werden die Argumente der Methode geändert

Dies ist der große in meinem Kopf. Dies ist der Grund, warum das Swizzling mit Standardmethoden nicht durchgeführt werden sollte. Sie ändern die an die Implementierung der ursprünglichen Methode übergebenen Argumente. Hier passiert es:

[self my_setFrame:frame];

Was diese Zeile tut, ist:

objc_msgSend(self, @selector(my_setFrame:), frame);

Welches wird die Laufzeit verwenden, um die Implementierung von nachzuschlagen my_setFrame:. Sobald die Implementierung gefunden wurde, ruft sie die Implementierung mit denselben Argumenten auf, die angegeben wurden. Die Implementierung, die es findet, ist die ursprüngliche Implementierung von setFrame:, also geht es weiter und nennt das, aber das _cmdArgument ist nicht so, setFrame:wie es sein sollte. Es ist jetzt my_setFrame:. Die ursprüngliche Implementierung wird mit einem Argument aufgerufen, das sie niemals erwartet hätte. Das ist nicht gut.

Es gibt eine einfache Lösung - verwenden Sie die oben definierte alternative Swizzling-Technik. Die Argumente bleiben unverändert!

Die Reihenfolge der Swizzles ist wichtig

Die Reihenfolge, in der Methoden durcheinander gebracht werden, spielt eine Rolle. Angenommen, setFrame:nur definiert ist auf NSView, stellen Sie sich diese Reihenfolge der Dinge vor:

[NSButton swizzle:@selector(setFrame:) with:@selector(my_buttonSetFrame:)];
[NSControl swizzle:@selector(setFrame:) with:@selector(my_controlSetFrame:)];
[NSView swizzle:@selector(setFrame:) with:@selector(my_viewSetFrame:)];

Was passiert, wenn die Methode NSButtonaktiviert ist? Nun die meisten Swizzling werden dafür sorgen , dass es nicht die Umsetzung des Ersatz setFrame:für alle Ansichten, so wird es nach oben zieht die Instanz - Methode. Dadurch wird die vorhandene Implementierung verwendet, um setFrame:die NSButtonKlasse neu zu definieren, sodass der Austausch von Implementierungen nicht alle Ansichten betrifft. Die vorhandene Implementierung ist die am definierte NSView. Das gleiche passiert beim Swizzling NSControl(wieder mit der NSViewImplementierung).

Wenn Sie setFrame:eine Schaltfläche aufrufen , wird daher Ihre Swizzled-Methode aufgerufen, und Sie springen direkt zu der setFrame:ursprünglich definierten Methode NSView. Die NSControlund NSViewswizzled Implementierungen werden nicht aufgerufen.

Aber was wäre, wenn die Reihenfolge wäre:

[NSView swizzle:@selector(setFrame:) with:@selector(my_viewSetFrame:)];
[NSControl swizzle:@selector(setFrame:) with:@selector(my_controlSetFrame:)];
[NSButton swizzle:@selector(setFrame:) with:@selector(my_buttonSetFrame:)];

Da die Ansicht Swizzling Platz zuerst stattfindet, wird die Steuer Swizzling der Lage sein, nach oben zu ziehen , die richtigen Methode. Ebenso , da die Steuer Swizzling vor dem Button Swizzling war, wird der Knopf nach oben zieht die umgestellte Umsetzung der Kontrolle setFrame:. Das ist etwas verwirrend, aber dies ist die richtige Reihenfolge. Wie können wir diese Ordnung sicherstellen?

Wieder nur verwenden load, um Dinge zu swizzeln. Wenn Sie einschalten loadund nur Änderungen an der zu ladenden Klasse vornehmen, sind Sie in Sicherheit. Die loadMethode garantiert, dass die Lademethode der Superklasse vor allen Unterklassen aufgerufen wird. Wir bekommen genau die richtige Bestellung!

Schwer zu verstehen (sieht rekursiv aus)

Wenn ich mir eine traditionell definierte Swizzled-Methode anschaue, denke ich, dass es wirklich schwer ist zu sagen, was los ist. Aber wenn man sich die alternative Art und Weise ansieht, wie wir oben geschwommen sind, ist das ziemlich leicht zu verstehen. Dieser ist bereits gelöst!

Schwer zu debuggen

Eine der Verwirrungen beim Debuggen ist das Sehen einer seltsamen Rückverfolgung, in der die Namen durcheinander gebracht werden und alles in Ihrem Kopf durcheinander gerät. Auch hier spricht die alternative Implementierung dies an. In Backtraces werden klar benannte Funktionen angezeigt. Trotzdem kann das Debuggen schwierig sein, da es schwer zu merken ist, welche Auswirkungen das Swizzling hat. Dokumentieren Sie Ihren Code gut (auch wenn Sie denken, dass Sie der einzige sind, der ihn jemals sehen wird). Befolgen Sie die guten Praktiken, und alles wird gut. Es ist nicht schwieriger zu debuggen als Multithread-Code.

Fazit

Das Methoden-Swizzling ist bei sachgemäßer Anwendung sicher. Eine einfache Sicherheitsmaßnahme, die Sie ergreifen können, besteht darin, nur einzuspritzen load. Wie viele Dinge in der Programmierung kann es gefährlich sein, aber wenn Sie die Konsequenzen verstehen, können Sie es richtig verwenden.


1 Mit der oben definierten Swizzling-Methode können Sie die Thread-Sicherheit erhöhen, wenn Sie Trampoline verwenden. Sie würden zwei Trampoline brauchen. Zu Beginn der Methode müssten Sie den Funktionszeiger storeeiner Funktion zuweisen, die sich dreht, bis sich die Adresse, auf die sie zeigt store, geändert hat. Dies würde jede Racebedingung vermeiden, in der die Swizzled-Methode aufgerufen wurde, bevor Sie den storeFunktionszeiger setzen konnten. Sie müssten dann ein Trampolin verwenden, wenn die Implementierung noch nicht in der Klasse definiert ist, und die Trampolin-Suche durchführen und die Super-Klassen-Methode ordnungsgemäß aufrufen. Wenn Sie die Methode so definieren, dass sie dynamisch nach der Super-Implementierung sucht, wird sichergestellt, dass die Reihenfolge der Swizzling-Aufrufe keine Rolle spielt.

wbyoung
quelle
24
Erstaunlich informative und technisch fundierte Antwort. Die Diskussion ist wirklich interessant. Vielen Dank, dass Sie sich die Zeit genommen haben, dies zu schreiben.
Ricardo Sanchez-Saez
Können Sie darauf hinweisen, ob es in App Stores akzeptabel ist, Ihre Erfahrungen zu verbessern? Ich verweise Sie auch auf stackoverflow.com/questions/8834294 .
Dickey Singh
3
Swizzling kann im App Store verwendet werden. Viele Apps und Frameworks tun dies (unsere eingeschlossen). Alles oben Genannte gilt immer noch, und Sie können keine privaten Methoden verwenden (tatsächlich können Sie dies technisch, aber Sie riskieren Ablehnung und die Gefahren sind für einen anderen Thread).
wbyoung
Erstaunliche Antwort. Aber warum sollte das Swizzling in class_swizzleMethodAndStore () statt direkt in + swizzle: with: store:? Warum diese zusätzliche Funktion?
Frizlab
2
@Frizlab gute Frage! Es ist wirklich nur eine Stilsache. Wenn Sie eine Reihe von Code schreiben, der direkt mit der Objective-C-Laufzeit-API (in C) zusammenarbeitet, ist es aus Gründen der Konsistenz hilfreich, ihn als C-Stil bezeichnen zu können. Der einzige Grund, an den ich denken kann, ist, wenn Sie etwas in reinem C geschrieben haben, dann ist es noch aufrufbarer. Es gibt jedoch keinen Grund, warum Sie mit der Objective-C-Methode nicht alles machen können.
wbyoung
12

Zuerst werde ich genau definieren, was ich unter Methoden-Swizzling verstehe:

  • Alle Anrufe, die ursprünglich an eine Methode (A genannt) gesendet wurden, an eine neue Methode (B) umleiten.
  • Wir besitzen Methode B.
  • Wir besitzen keine Methode A.
  • Methode B erledigt einige Arbeiten und ruft dann Methode A auf.

Methoden-Swizzling ist allgemeiner als dies, aber dies ist der Fall, an dem ich interessiert bin.

Gefahren:

  • Änderungen in der ursprünglichen Klasse . Wir besitzen nicht die Klasse, die wir schwirren. Wenn sich die Klasse ändert, funktioniert unser Swizzle möglicherweise nicht mehr.

  • Schwer zu pflegen . Sie müssen nicht nur die Swizzled-Methode schreiben und pflegen. Sie müssen den Code schreiben und pflegen, der den Swizzle ausführt

  • Schwer zu debuggen . Es ist schwierig, dem Fluss eines Sprühregens zu folgen. Einige Leute bemerken möglicherweise nicht einmal, dass der Sprühregen durchgeführt wurde. Wenn durch das Swizzle Fehler auftreten (möglicherweise aufgrund von Änderungen in der ursprünglichen Klasse), sind diese schwer zu beheben.

Zusammenfassend sollten Sie das Swizzeln auf ein Minimum beschränken und überlegen, wie sich Änderungen in der ursprünglichen Klasse auf Ihr Swizzle auswirken können. Außerdem sollten Sie klar kommentieren und dokumentieren, was Sie tun (oder es einfach ganz vermeiden).

Robert
quelle
@jeder Ich habe deine Antworten in einem schönen Format zusammengefasst. Fühlen Sie sich frei, es zu bearbeiten / hinzuzufügen. Danke für deinen Beitrag.
Robert
Ich bin ein Fan Ihrer Psychologie. "Mit großer Swizzling-Kraft geht eine große Swizzling-Verantwortung einher."
Jacksonkr
7

Es ist nicht das Aufwirbeln selbst, das wirklich gefährlich ist. Das Problem ist, wie Sie sagen, dass es häufig verwendet wird, um das Verhalten von Framework-Klassen zu ändern. Es wird davon ausgegangen, dass Sie etwas über die Funktionsweise dieser Privatklassen wissen, das "gefährlich" ist. Selbst wenn Ihre Änderungen heute funktionieren, besteht immer die Möglichkeit, dass Apple die Klasse in Zukunft ändert und Ihre Änderung bricht. Wenn es viele verschiedene Apps tun, ist es für Apple umso schwieriger, das Framework zu ändern, ohne viel vorhandene Software zu beschädigen.

Caleb
quelle
Ich würde sagen, solche Entwickler sollten ernten, was sie säen - sie haben ihren Code eng an eine bestimmte Implementierung gekoppelt. Es ist daher ihre Schuld, wenn sich diese Implementierung auf subtile Weise ändert, die ihren Code nicht hätte beschädigen dürfen, wenn sie nicht ausdrücklich entschieden hätten, ihren Code so eng wie sie zu koppeln.
Arafangion
Sicher, aber sagen wir, dass eine sehr beliebte App unter der nächsten Version von iOS kaputt geht. Es ist leicht zu sagen, dass es die Schuld des Entwicklers ist und sie es besser wissen sollten, aber es lässt Apple in den Augen des Benutzers schlecht aussehen. Ich sehe keinen Schaden darin, Ihre eigenen Methoden oder sogar Klassen zu durchsuchen, wenn Sie dies tun möchten, abgesehen von Ihrem Standpunkt, dass dies den Code etwas verwirrend machen kann. Es wird etwas riskanter, wenn Sie Code swizzeln, der von jemand anderem gesteuert wird - und genau in dieser Situation scheint das Swizzling am verlockendsten zu sein.
Caleb
Apple ist nicht der einzige Anbieter von Basisklassen, die über siwzzling geändert werden können. Ihre Antwort sollte so bearbeitet werden, dass sie alle einschließt.
AR
@AR Vielleicht, aber die Frage ist mit iOS und iPhone gekennzeichnet, daher sollten wir sie in diesem Zusammenhang berücksichtigen. Angesichts der Tatsache, dass iOS-Apps andere Bibliotheken und Frameworks als die von iOS bereitgestellten statisch verknüpfen müssen, ist Apple tatsächlich die einzige Entität, die die Implementierung von Framework-Klassen ohne Beteiligung von App-Entwicklern ändern kann. Ich stimme jedoch dem Punkt zu, dass ähnliche Probleme andere Plattformen betreffen, und ich würde sagen, dass der Rat auch über das Swizzling hinaus verallgemeinert werden kann. Im Allgemeinen lautet der Rat: Behalten Sie Ihre Hände für sich. Vermeiden Sie es, Komponenten zu ändern, die von anderen Personen gewartet werden.
Caleb
Method Swizzling kann so gefährlich sein. Aber wenn die Frameworks herauskommen, lassen sie die vorherigen nicht vollständig aus. Sie müssen noch das Basis-Framework aktualisieren, das Ihre App erwartet. und dieses Update würde Ihre App beschädigen. Es ist wahrscheinlich kein so großes Problem, wenn das iOS aktualisiert wird. Mein Verwendungsmuster bestand darin, den Standard-ReuseIdentifier zu überschreiben. Da ich keinen Zugriff auf die Variable _reuseIdentifier hatte und sie nicht ersetzen wollte, es sei denn, sie wurde nicht bereitgestellt, bestand meine einzige Lösung darin, jede einzelne zu unterklassifizieren und die Wiederverwendungskennung anzugeben oder bei Null zu wechseln und zu überschreiben. Der Implementierungstyp ist der Schlüssel ...
The Lazy Coder
5

Sorgfältig und weise eingesetzt, kann es zu elegantem Code führen, aber normalerweise führt es nur zu verwirrendem Code.

Ich sage, dass es verboten werden sollte, es sei denn, Sie wissen zufällig, dass es eine sehr elegante Gelegenheit für eine bestimmte Entwurfsaufgabe darstellt, aber Sie müssen klar wissen, warum es für die Situation gut gilt und warum Alternativen für die Situation nicht elegant funktionieren .

Eine gute Anwendung des Methoden-Swizzling ist beispielsweise das Swizzling, mit dem ObjC die Key Value-Beobachtung implementiert.

Ein schlechtes Beispiel könnte darin bestehen, sich auf Methoden-Swizzling zu verlassen, um Ihre Klassen zu erweitern, was zu einer extrem hohen Kopplung führt.

Arafangion
quelle
1
-1 für die Erwähnung von KVO - im Zusammenhang mit Methoden-Swizzling . isa swizzling ist nur etwas anderes.
Nikolai Ruhe
@NikolaiRuhe: Bitte zögern Sie nicht, Referenzen anzugeben, damit ich erleuchtet werden kann.
Arafangion
Hier ist ein Verweis auf die Implementierungsdetails von KVO . Das Methoden-Swizzling wird in CocoaDev beschrieben.
Nikolai Ruhe
5

Obwohl ich diese Technik angewendet habe, möchte ich darauf hinweisen, dass:

  • Es verschleiert Ihren Code, da es nicht dokumentierte, wenn auch gewünschte Nebenwirkungen verursachen kann. Wenn jemand den Code liest, ist er / sie möglicherweise nicht über das erforderliche Nebenwirkungsverhalten informiert, es sei denn, er / sie erinnert sich daran, die Codebasis zu durchsuchen, um festzustellen, ob sie durcheinander gebracht wurde. Ich bin mir nicht sicher, wie ich dieses Problem beheben kann, da es nicht immer möglich ist, jeden Ort zu dokumentieren, an dem der Code vom Verhalten der Nebenwirkung abhängt.
  • Dies kann dazu führen, dass Ihr Code weniger wiederverwendbar ist, da jemand, der ein Codesegment findet, das von dem Verhalten abhängt, das er an anderer Stelle verwenden möchte, es nicht einfach ausschneiden und in eine andere Codebasis einfügen kann, ohne auch die Swizzled-Methode zu finden und zu kopieren.
user3288724
quelle
4

Ich bin der Meinung, dass die größte Gefahr darin besteht, viele unerwünschte Nebenwirkungen völlig zufällig zu verursachen. Diese Nebenwirkungen können sich als "Fehler" darstellen, die Sie wiederum auf den falschen Weg führen, um die Lösung zu finden. Nach meiner Erfahrung ist die Gefahr unleserlicher, verwirrender und frustrierender Code. Ein bisschen wie wenn jemand Funktionszeiger in C ++ überbeansprucht.

AR
quelle
Ok, das Problem ist, dass das Debuggen schwierig ist. Die Probleme werden dadurch verursacht, dass Prüfer nicht erkennen / vergessen, dass der Code durcheinander gebracht wurde und beim Debuggen an der falschen Stelle suchen.
Robert
3
Ja so ziemlich. Bei Überbeanspruchung können Sie auch in eine endlose Kette oder ein Netz von Sprudeln geraten. Stellen Sie sich vor, was passieren könnte, wenn Sie irgendwann in der Zukunft nur einen von ihnen ändern? Ich vergleiche die Erfahrung mit dem Stapeln von Teetassen oder dem Spielen von 'Code Jenga'
AR
4

Möglicherweise erhalten Sie einen seltsam aussehenden Code wie

- (void)addSubview:(UIView *)view atIndex:(NSInteger)index {
    //this looks like an infinite loop but we're swizzling so default will get called
    [self addSubview:view atIndex:index];

vom tatsächlichen Produktionscode im Zusammenhang mit etwas UI-Magie.

Quantumpotato
quelle
3

Methoden-Swizzling kann beim Unit-Test sehr hilfreich sein.

Sie können ein Scheinobjekt schreiben und dieses Scheinobjekt anstelle des realen Objekts verwenden lassen. Ihr Code soll sauber bleiben und Ihr Unit-Test hat ein vorhersehbares Verhalten. Angenommen, Sie möchten Code testen, der CLLocationManager verwendet. Ihr Komponententest könnte startUpdatingLocation so schnell wie möglich aktivieren, sodass Ihrem Delegaten eine vorgegebene Gruppe von Speicherorten zugeführt wird und sich Ihr Code nicht ändern muss.

user3288724
quelle
isa-swizzling wäre eine bessere Wahl.
Vikingosegundo