2014-01-26 15 views
8

Wie wir wissen, mit ARC brauchen wir eine __bridge eine ID zu einem void * zu konvertieren:__bridge für Methodenargumente nicht benötigt?

void *t = (void *)self;   // ERROR: Cast of ... requires a bridged cast 
void *t = (__bridge void *)self; // CORRECT 

So sind C-Funktion aufruft:

void f(void *t) { 
    .... 
} 

f((void *)self);   // ERROR 
f((__bridge void *)self); // CORRECT 

Ich denke, das auch für die Methoden halten sollte, und in der Tat diese Beginning ARC in iOS 5 Tutorial gibt folgendes Beispiel, und sagt, dass die __bridge benötigt wird:

MyClass *myObject = [[MyClass alloc] init]; 
[UIView beginAnimations:nil context:(__bridge void *)myObject]; 

Allerdings habe ich heute versehentlich einen __bridge in einem Methodenaufruf in einem meiner Programme gelöscht, und der Code kompiliert und lief ohne jedes Problem. Die __bridge in dem obigen Beispiel scheint nicht notwendig zu sein:

[UIView beginAnimations:nil context:(void *)myObject]; // COMPILED OK 

Ist das richtig? Ist die __bridge in diesem Fall wirklich unnötig? Oder das Entfernen ändert sich, was der Code bedeutet?

Antwort

6

Diese im ARC docs section 3.3.3 (Hervorhebung von mir) bedeckt ist:

3.3.3 Conversion from retainable object pointer type in certain contexts

[beginning Apple 4.0, LLVM 3.1]

If an expression of retainable object pointer type is explicitly cast to a C retainable pointer type, the program is ill-formed as discussed above unless the result is immediately used:

  • to initialize a parameter in an Objective-C message send where the parameter is not marked with the cf_consumed attribute, or to
  • initialize a parameter in a direct call to an audited function where the parameter is not marked with the cf_consumed attribute.

in Ihrem Code myObject ist ein "beibehaltener Objektzeiger". Ein "C retainable pointer type" enthält void* (dies ist eine leicht nachlässige Definition, die sie als Platzhalter verwenden, da Core Foundation "Objekte" oft void* sind).

So kann ein ObjC-Objekt implizit in einen void* konvertiert werden, wenn es als Methodenparameter verwendet wird. In diesem Fall gibt es keine zusätzliche Speicherverwaltungssemantik (d. H. Es entspricht einer __bridge Umwandlung). Section 7.8 warnt uns, dass void* in Zukunft nicht mehr so ​​behandelt werden kann, aber darüber würde ich mir keine Sorgen machen. Wenn es passiert, wird das Hinzufügen der __bridge trivial sein.

Die eine Sache zu beachten ist, dass myObject hier nicht geschützt ist.Es liegt an Ihnen, sicherzustellen, dass es auf andere Weise beibehalten wird, bis die Animationen abgeschlossen sind, oder Sie können abstürzen.

+0

Sehr interessant und gut gesichtet. +1, weil du mir noch einen weiteren Grund gegeben hast, ARK zu hassen ;-) –

2

__bridge wird für die Übergabe von Variablen/Referenzen (wie Retain-Anzahl) verwendet, die CAPI zu objective-C oder objective-C zu API ist.

Gehen Sie durch Clang's doc:

Bridged casts

A bridged cast is a C-style cast annotated with one of three keywords:

(__bridge T) op casts the operand to the destination type T. If T is a retainable object pointer type, then op must have a 

non-retainable pointer type. If T is a non-retainable pointer type, then op must have a retainable object pointer type. Otherwise the cast is ill-formed. There is no transfer of ownership, and ARC inserts no retain operations. (__bridge_retained T) op casts the operand, which must have retainable object pointer type, to the destination type, which must be a non-retainable pointer type. ARC retains the value, subject to the usual optimizations on local values, and the recipient is responsible for balancing that +1. (__bridge_transfer T) op casts the operand, which must have non-retainable pointer type, to the destination type, which must be a retainable object pointer type. ARC will release the value at the end of the enclosing full-expression, subject to the usual optimizations on local values.

These casts are required in order to transfer objects in and out of ARC control; see the rationale in the section on conversion of retainable object pointers.

Using a __bridge_retained or __bridge_transfer cast purely to convince ARC to emit an unbalanced retain or release, respectively, is poor form.

Jetzt

void * t = (void *) selbst; // FEHLER: Besetzung von ... erfordert eine überbrückte Besetzung Warum ist das falsch, weil Sie versuchen, die Referenz von Objective-C auf C zu übertragen. Es ist nicht gelungen, die Referenz zu übergeben.

void * t = (__bridge void *) selbst; // RICHTIG Warum korrigieren Sie, weil Sie Ihre Ziel-C-Referenz auf C übertragen haben. Nach dem Dokument von LLVM. Siehe oben angegebene Regeln.

MyClass *myObject = [[MyClass alloc] init]; 
[UIView beginAnimations:nil context:(__bridge void *)myObject]; 

Above Linien sind vollständig noch in Ordnung, weil Sie C Referenzart Kontext übergeben statt NULL