Ich wechsle eine Anwendung von Objective-C zu Swift, für die ich einige Kategorien mit gespeicherten Eigenschaften habe, zum Beispiel:
@interface UIView (MyCategory)
- (void)alignToView:(UIView *)view
alignment:(UIViewRelativeAlignment)alignment;
- (UIView *)clone;
@property (strong) PFObject *xo;
@property (nonatomic) BOOL isAnimating;
@end
Da Swift-Erweiterungen solche gespeicherten Eigenschaften nicht akzeptieren, weiß ich nicht, wie ich die gleiche Struktur wie der Objc-Code beibehalten soll. Gespeicherte Eigenschaften sind für meine App sehr wichtig, und ich glaube, Apple muss eine Lösung dafür in Swift erstellt haben.
Wie von jou gesagt, suchte ich tatsächlich nach zugehörigen Objekten, also tat ich es (in einem anderen Kontext):
import Foundation
import QuartzCore
import ObjectiveC
extension CALayer {
var shapeLayer: CAShapeLayer? {
get {
return objc_getAssociatedObject(self, "shapeLayer") as? CAShapeLayer
}
set(newValue) {
objc_setAssociatedObject(self, "shapeLayer", newValue, UInt(OBJC_ASSOCIATION_RETAIN))
}
}
var initialPath: CGPathRef! {
get {
return objc_getAssociatedObject(self, "initialPath") as CGPathRef
}
set {
objc_setAssociatedObject(self, "initialPath", newValue, UInt(OBJC_ASSOCIATION_RETAIN))
}
}
}
Aber ich bekomme eine EXC_BAD_ACCESS, wenn ich mache:
class UIBubble : UIView {
required init(coder aDecoder: NSCoder) {
...
self.layer.shapeLayer = CAShapeLayer()
...
}
}
Irgendwelche Ideen?
ios
swift
associated-object
Marcos Duarte
quelle
quelle
Antworten:
Die API für zugeordnete Objekte ist etwas umständlich zu verwenden. Sie können den größten Teil der Kesselplatte mit einer Hilfsklasse entfernen.
Vorausgesetzt, Sie können der Objective-C-Klasse eine Eigenschaft besser lesbar "hinzufügen":
Wie für die Lösung:
quelle
NSNumber
oder speichernNSValue
und zusätzliche Accessorenpaare schreiben, die von den gewünschten Typen sind (Int, Bool usw.).NSObjectProtocol
[String]?
ist eine Struktur, dies ist der gleiche Fall wie für Int, Bool. Sie könnenNSArray
eine Sammlung vonNSString
Instanzen verwenden.Wie in Objective-C können Sie vorhandenen Klassen keine gespeicherten Eigenschaften hinzufügen. Wenn Sie eine Objective-C-Klasse erweitern (
UIView
definitiv eine), können Sie weiterhin zugeordnete Objekte verwenden , um gespeicherte Eigenschaften zu emulieren:für Swift 1
Der Zuordnungsschlüssel ist ein Zeiger, der für jede Zuordnung eindeutig sein sollte. Dazu erstellen wir eine private globale Variable und verwenden deren Speicheradresse als Schlüssel für den
&
Operator. Sehen Sie sich die Verwendung von Swift mit Cocoa und Objective-C auf mehr Details , wie Zeiger in Swift abgewickelt.AKTUALISIERT für Swift 2 und 3
AKTUALISIERT für Swift 4
In Swift 4 ist es viel einfacher. Die Holder-Struktur enthält den privaten Wert, den unsere berechnete Eigenschaft der Welt zur Verfügung stellt, und gibt stattdessen die Illusion eines Verhaltens gespeicherter Eigenschaften.
Quelle
quelle
objc_AssociationPolicy
, danke! Ich habe die Antwort aktualisiertIch denke, ich habe eine Methode gefunden, die sauberer funktioniert als die oben genannten, da keine globalen Variablen erforderlich sind. Ich habe es von hier bekommen: http://nshipster.com/swift-objc-runtime/
Das Wesentliche ist, dass Sie eine Struktur wie folgt verwenden:
UPDATE für Swift 2
quelle
Die von Ihnen erwähnte Lösung unterstützt keine Werttypen , dies funktioniert auch gut mit ihnen
Wrapper
Eine mögliche Klassenerweiterung (Anwendungsbeispiel):
Dies ist wirklich eine großartige Lösung. Ich wollte ein weiteres Anwendungsbeispiel hinzufügen, das Strukturen und Werte enthält, die keine Optionen sind. Außerdem können die AssociatedKey-Werte vereinfacht werden.
quelle
lift
Methode und dieLifted
Klasse verwendet, sie sollten jedochgetAssociatedObject
&setAssociatedObject
Funktionen verwenden. Der Klarheit halber werde ich in Klammern neben der Kopfzeile "Anwendungsbeispiel" einfügen.Sie können keine Kategorien (Swift-Erweiterungen) mit neuem Speicher definieren. Alle zusätzlichen Eigenschaften müssen berechnet und nicht gespeichert werden. Die Syntax funktioniert für Ziel C, da
@property
in einer Kategorie im Wesentlichen "Ich werde den Getter und Setter bereitstellen" bedeutet. In Swift müssen Sie diese selbst definieren, um eine berechnete Eigenschaft zu erhalten. etwas wie:Sollte gut funktionieren. Denken Sie daran, dass Sie keine neuen Werte im Setter speichern können, sondern nur mit dem vorhandenen verfügbaren Klassenstatus arbeiten.
quelle
Meine $ 0,02. Dieser Code ist in Swift 2.0 geschrieben
Ich habe viele Lösungen ausprobiert und festgestellt, dass dies die einzige Möglichkeit ist, eine Klasse tatsächlich um zusätzliche variable Parameter zu erweitern.
quelle
type 'AssociatedKeys' cannot be defined within a protocol extension
...Warum sich auf die objc-Laufzeit verlassen? Ich verstehe den Punkt nicht. Wenn Sie Folgendes verwenden, erzielen Sie fast das gleiche Verhalten einer gespeicherten Eigenschaft, indem Sie nur einen reinen Swift-Ansatz verwenden :
quelle
Ich bevorzuge Code in reinem Swift und verlasse mich nicht auf das Objective-C-Erbe. Aus diesem Grund habe ich eine reine Swift-Lösung mit zwei Vor- und zwei Nachteilen geschrieben.
Vorteile:
Reiner Swift-Code
Funktioniert mit Klassen und Vervollständigungen oder genauer mit
Any
ObjektenNachteile:
Code sollte eine Methode aufrufen
willDeinit()
, um Objekte freizugeben, die mit einer bestimmten Klasseninstanz verknüpft sind, um Speicherverluste zu vermeidenSie können für genau dieses Beispiel keine Erweiterung direkt auf UIView
var frame
vornehmen, da die Erweiterung auf UIView nicht Teil der Klasse ist.BEARBEITEN:
quelle
extensionPropertyStorage
wird standardmäßig mit allen Instanzen geteilt. Es ist eine globale Variable (Dictionary), die zuerst die UILabel-Instanz (NSObject
) und dann ihre Eigenschaft ([String: Any]
) de-referenziert .class
Immobilien;)frame
ist eine Instanzeigenschaft. Woher kommt Klasseneigentum?Mit Obj-c Categories können Sie nur Methoden hinzufügen, keine Instanzvariablen.
In Ihrem Beispiel haben Sie @property als Verknüpfung zum Hinzufügen von Getter- und Setter-Methodendeklarationen verwendet. Sie müssen diese Methoden noch implementieren.
In ähnlicher Weise können Sie in Swift Verwendungserweiterungen hinzufügen, um Instanzmethoden, berechnete Eigenschaften usw. hinzuzufügen, jedoch keine gespeicherten Eigenschaften.
quelle
Ich bekomme auch ein EXC_BAD_ACCESS-Problem. Der Wert in
objc_getAssociatedObject()
undobjc_setAssociatedObject()
sollte ein Objekt sein. Und dasobjc_AssociationPolicy
sollte zum Objekt passen.quelle
Ich habe versucht, objc_setAssociatedObject zu verwenden, wie in einigen der Antworten hier erwähnt, aber nachdem ich einige Male damit gescheitert war, trat ich zurück und stellte fest, dass es keinen Grund gibt, warum ich das brauche. Ausgehend von einigen der hier vorgestellten Ideen habe ich diesen Code entwickelt, in dem einfach ein Array meiner zusätzlichen Daten (in diesem Beispiel MyClass) gespeichert ist, die von dem Objekt indiziert werden, mit dem ich sie verknüpfen möchte:
quelle
Hier ist eine vereinfachte und aussagekräftigere Lösung. Es funktioniert sowohl für Wert- als auch für Referenztypen. Der Ansatz des Hebens ist der Antwort von @HepaKKes entnommen.
Assoziationscode:
Anwendungsbeispiel:
1) Erstellen Sie eine Erweiterung und ordnen Sie ihr Eigenschaften zu. Verwenden wir sowohl Wert- als auch Referenztyp-Eigenschaften.
2) Jetzt können Sie nur noch reguläre Eigenschaften verwenden:
Mehr Details:
quelle
Ein weiteres Beispiel für die Verwendung von Objective-C-zugeordneten Objekten und berechneten Eigenschaften für Swift 3 und Swift 4
quelle
Wenn Sie ein benutzerdefiniertes Zeichenfolgenattribut für eine UIView festlegen möchten, habe ich dies in Swift 4 so gemacht
Erstellen Sie eine UIView-Erweiterung
So verwenden Sie diese Erweiterung
quelle
Wie wäre es mit dem Speichern einer statischen Karte in einer Klasse, die sich wie folgt erweitert:
quelle
Ich habe versucht, Eigenschaften mithilfe von objc_getAssociatedObject, objc_setAssociatedObject, ohne Glück zu speichern. Mein Ziel war es, eine Erweiterung für UITextField zu erstellen, um die Länge der Texteingabezeichen zu überprüfen. Der folgende Code funktioniert gut für mich. Hoffe das wird jemandem helfen.
quelle
_min
und Sie_max
sind global und werden in allen Instanzen des UITextField gleich sein? Auch wenn es für Sie arbeitet, ist diese Antwort nicht verwendet , weil Marcos zu fragen Instanz Variablen.Hier ist eine Alternative, die auch funktioniert
quelle
Ich fand diese Lösung praktischer
AKTUALISIERT für Swift 3
... dann in deinem Code
quelle