ARC und Bridged Cast

166

Mit ARC, kann ich nicht mehr gegossen CGColorRefzu id. Ich habe gelernt, dass ich eine überbrückte Besetzung machen muss. Laut Clang Docs :

Eine überbrückte Besetzung ist eine Besetzung im C-Stil, die mit einem von drei Schlüsselwörtern versehen ist:

(__bridge T) opwandelt den Operanden in den Zieltyp um T. Wenn T es sich um einen Zeigertyp für einbehaltbares Objekt handelt, opmuss es einen nicht behaltbaren Zeigertyp haben. Wenn Tes sich um einen nicht beibehaltenen Zeigertyp handelt, muss op über einen beibehaltenen Objektzeigertyp verfügen. Ansonsten ist die Besetzung schlecht geformt. Es findet keine Eigentumsübertragung statt, und ARC fügt keine Aufbewahrungsvorgänge ein.

(__bridge_retained T) opwandelt den Operanden, der den Zeigertyp des beibehaltenen Objekts haben muss, in den Zieltyp um, der ein nicht beibehaltener Zeigertyp sein muss. ARC behält den Wert bei, vorbehaltlich der üblichen Optimierungen der lokalen Werte, und der Empfänger ist dafür verantwortlich, diese +1 auszugleichen.

(__bridge_transfer T) opwandelt den Operanden, der einen nicht beibehaltenen Zeigertyp haben muss, in den Zieltyp um, der ein beibehaltener Objektzeigertyp sein muss. ARC gibt den Wert am Ende des einschließenden vollständigen Ausdrucks frei, vorbehaltlich der üblichen Optimierungen für lokale Werte.

Diese Casts sind erforderlich, um Objekte in und außerhalb der ARC-Kontrolle zu übertragen. Weitere Informationen finden Sie im Abschnitt zur Konvertierung von Zeigern für beibehaltene Objekte.

Die Verwendung von a __bridge_retainedoder __bridge_transfercast nur, um ARC davon zu überzeugen, eine unausgeglichene Retention bzw. Freigabe zu emittieren, ist eine schlechte Form.

In welchen Situationen würde ich jeden verwenden?

Hat beispielsweise CAGradientLayereine colorsEigenschaft, die ein Array von CGColorRefs akzeptiert . Ich vermute, dass ich __brigehier verwenden sollte, aber genau, warum ich sollte (oder nicht), ist unklar.

Morgenlos
quelle
17
Haben Sie die WWDC 2011-Sitzung 323 schon gesehen? Das erklärt ARC weitaus besser als ich hier könnte. Es deckt alle Details von Anfang bis Ende ab. Es ist ein Muss für jeden Mac / iOS-Entwickler.
Rbrown
Dies könnte auch helfen: stackoverflow.com/questions/14352494/…
Ewan Mellor
Link zur WWDC-Sitzung, es war nicht trivial zu finden: developer.apple.com/videos/play/wwdc2011/323 - Relevantes Bit ist um 23:15 Uhr
Daniel

Antworten:

215

Ich stimme zu, dass die Beschreibung verwirrend ist. Da ich sie gerade verstanden habe, werde ich versuchen zusammenzufassen:

  • (__bridge_transfer <NSType>) opoder wird alternativ CFBridgingRelease(op)verwendet, um eine Aufbewahrungszahl von a zu verbrauchen, CFTypeRefwährend sie an ARC übertragen wird. Dies könnte auch durch dargestellt werdenid someObj = (__bridge <NSType>) op; CFRelease(op);

  • (__bridge_retained <CFType>) opoder wird alternativ CFBridgingRetain(op)verwendet, um ein NSObjectCF-Land zu übergeben, während es eine +1 Retain-Zählung erhält . Sie sollten a, das CFTypeRefSie auf diese Weise erstellen, genauso behandeln, wie Sie ein Ergebnis von behandeln würden CFStringCreateCopy(). Dies könnte auch durch dargestellt werdenCFRetain((__bridge CFType)op); CFTypeRef someTypeRef = (__bridge CFType)op;

  • __bridgeWirft nur zwischen Zeigerland und Objektiv-C-Objektland. Wenn Sie nicht geneigt sind, die oben genannten Konvertierungen zu verwenden, verwenden Sie diese.

Vielleicht ist das hilfreich. Ich selbst bevorzuge die CFBridging…Makros gegenüber den einfachen Darstellern.

Monkeydom
quelle
Wird die Anzahl der Objekte, die beibehalten werden, bei Verwendung von __bridge_transfer um 1 Bogen erhöht? Andernfalls scheint das Objekt in dem Moment, in dem CFRelease () aufgerufen wird, verschwunden zu sein und auf nichts zu zeigen. Reduziert ARC bei Verwendung von __bridge_retain die Retentionszahl des Ops um 1? Andernfalls scheint das Objekt niemals ordnungsgemäß freigegeben zu werden.
Tony
2
Sobald Sie im ARC-Land sind, denken Sie nicht mehr daran, die Anzahl zu behalten, sondern nur noch an starke und schwache Referenzen.
Monkeydom
4
Ja, wenn Sie sich nur im Bogenland befinden, würde stark / schwach ausreichen. Wenn Sie jedoch Objekte zwischen Bogen- und Nicht-Bogen-Umgebungen wechseln, müssen Sie immer noch über die Auswirkungen der Beibehaltung der Anzahl unter der Haube nachdenken
Tony
3
Nicht wirklich. Sie müssen nur daran denken, in ARC-Land ein- und auszusteigen. Und das erinnert ziemlich an das Erfassen von Autoreleasing. (Interessanterweise: ARC behebt ein allgemeines Muster wie das Herausnehmen eines Objekts aus einem Wörterbuch und das anschließende Entfernen vor der Verwendung usw.)
monkeydom
3
Die Verwendung des Analysator-Tools (Umschalt + Befehl + B) kann bei der Lösung solcher Zweifel hilfreich sein, da in einer natürlichen Sprache angezeigt wird, ob der aktuelle Code Speicher verliert. In diesem Fall verwenden Sie wahrscheinlich einen Halteguss, während Sie einen nicht Halteguss verwenden sollten. Wenn der Analyzer Sie vor nichts in diesen Codezeilen warnt, machen Sie es wahrscheinlich gut mit dem aktuellen Code
Fabio Napodano
55

Ich habe in der iOS-Dokumentation eine andere Erklärung gefunden, die meiner Meinung nach leichter zu verstehen ist:

  • __bridge überträgt einen Zeiger zwischen Objective-C und Core Foundation ohne Eigentumsübertragung.

  • __bridge_retained (CFBridgingRetain)Wirft einen Objective-C- Zeiger auf einen Core Foundation- Zeiger und überträgt Ihnen auch das Eigentum.

    Sie sind dafür verantwortlich , CFRelease oder eine verwandte Funktion aufzurufen, um das Eigentum an dem Objekt aufzugeben.

  • __bridge_transfer (CFBridgingRelease)Verschiebt einen Nicht-Objective-C- Zeiger auf Objective-C und überträgt auch das Eigentum an ARC.

    ARC ist dafür verantwortlich, das Eigentum an dem Objekt aufzugeben.

Quelle: Gebührenfreie überbrückte Typen

gregschlom
quelle
33

In diesem speziellen Fall empfiehlt Apple unter iOS die Verwendung von UIColor und seiner -CGColorMethode, um CGColorRef in das colorsNSArray zurückzugeben. In den Versionshinweisen für den Übergang zu ARC im Abschnitt "Der Compiler behandelt von Cocoa-Methoden zurückgegebene CF-Objekte" wird angegeben, dass die Verwendung einer Methode, mit -CGColorder ein Core Foundation-Objekt zurückgegeben wird, vom Compiler automatisch ordnungsgemäß behandelt wird.

Daher schlagen sie vor, Code wie den folgenden zu verwenden:

CAGradientLayer *gradientLayer = (CAGradientLayer *)[self layer];
gradientLayer.colors = [NSArray arrayWithObjects:(id)[[UIColor darkGrayColor] CGColor],
                                                 (id)[[UIColor lightGrayColor] CGColor], nil];

Beachten Sie, dass im Beispielcode von Apple ab sofort die oben angegebene (ID-) Besetzung fehlt, die weiterhin erforderlich ist, um einen Compilerfehler zu vermeiden.

Brad Larson
quelle
Wenn Sie es vorziehen, können Sie normalerweise davonkommen, indem Sie nur das erste der Objekte auf (id) anstatt auf alle werfen.
Philippe Sabourin
1
Diese Frage bezieht sich auf das Casting mit ARC, bei dem der von Ihnen eingefügte Code nicht legal ist.
Joey Hagedorn
11
@JoeyHagedorn - Vielleicht haben Sie meinen Verweis auf die ARC-Dokumentation im ersten Satz meiner Antwort verpasst, aber dies gilt nicht nur für ARC, sondern ist auch der empfohlene Ansatz für die Bereitstellung von CGColorRef-Verweisen in NSArrays mit diesen UIColor-Konvertermethoden. Ich und viele andere verwenden genau diesen Code in ARC-fähigen Anwendungen. Das sofortige Umwandeln einer Methode, die ein Core Foundation-Objekt zurückgibt, nach (id) überbrückt dieses Objekt automatisch ordnungsgemäß mit ARC.
Brad Larson