6.5Über diese Brücke musst du gehen
Core Foundation ist ein C-Framework, das die Grundlage für das Foundation-Framework
bildet. Es stellt allerdings Funktionen und keine Objective-C-Klassen bereit, und
so müssen Sie die Parameter und Rückgabewerte gegebenenfalls von den Klassen auf die
entsprechenden Datentypen übertragen. Das ist jedoch glücklicherweise in den meisten
Fällen nicht sehr schwer, da Apple hierfür einen speziellen Mechanismus – die Toll-free Bridge – bereitstellt, der Klassen auf Datentypen und umgekehrt abbildet. Die Toll-free
Bridge funktioniert allerdings nur mit Datentypen und den zugehörigen Klassen von
Apple; Sie können diesen Mechanismus leider nicht auf andere Klassen und Datentypen
ausdehnen.
[Anm.: Zumindest nicht, wenn Sie Ihre App durch den Review-Prozess in den App Store bekommen
möchten.]
Beim manuellen Referenzzählen besteht die Brücke einfach aus einem Cast. Sie können also beispielsweise ein Objekt der Klasse NSString auf eine Referenz des Typs CFStringRef und umgekehrt abbilden:
CFStringRef theReference = (CFStringRef)theString;
NSString *theValue = (NSString *)theReference;
Listing 6.104 Toll-free Bridge
6.5.1Toll-free Bridging und ARC

Beim automatischen Referenzzählen müssen Sie dem Compiler hingegen einen zusätzlichen Hinweis für die Speicherverwaltung geben. In Core Foundation erfolgt die Speicherverwaltung ja nach wie vor explizit durch Aufrufe der Funktionen CFRetain und CFRelease, und deshalb müssen Sie dem Compiler mitteilen, wie Sie das Core-Foundation-Objekt verwalten möchten.
Im einfachsten Fall wollen Sie die Eigentümerschaft nicht übertragen, und die Speicherverwaltung bleibt beim Ursprungsobjekt. Dafür nehmen Sie das Schlüsselwort __bridge in den Cast mit auf.
CFStringRef *theReference = CFStringCreateCopy(...);
NSString *theString = (__bridge NSString *)theReference;
...
CFRelease(theReference);
Listing 6.105 Cast ohne Übertragung der Eigentümerschaft
Listing 6.105 überträgt die Core-Foundation-Referenz theReference ohne die Eigentümerschaft auf eine Referenz von NSString. Dadurch erzeugt der ARC-Compiler keinen Code, um die Zeichenkette, auf die theString verweist, freizugeben. Damit kein Speicherleck entsteht, müssen Sie also die Core-Foundation-Referenz durch CFRelease freigeben. Auch bei dem umgekehrten Cast in Listing 6.106 überträgt der ARC-Compiler nicht die Eigentümerschaft. Dadurch sorgt er für die Freigabe der Zeichenkette, auf die theString verweist. Ein Aufruf von CFRelease für theReference würde bei diesem Beispiel wahrscheinlich zu einem Speicherzugriffsfehler führen.
NSString *theString = ...;
CFStringRef theReference = (__bridge CFStringRef)theString;
Listing 6.106 Umgekehrter Cast ohne Übertragung der Eigentümerschaft
Listing 6.60 enthält einen solchen Cast: (__bridge CFURLRef)theURL. Hier soll die Verwaltung der Eigentümerschaft von theURL beim ARC-Compiler bleiben, da ja die Funktion CGImageSourceCreateWithURL sie nicht übernimmt. Die Funktion CGImageSourceCreateImageAtIndex liefert hingegen ein Core-Graphics-Bild zurück, dessen Eigentümer die Methode ist. Sie muss nun das Bild in das Array einfügen und dabei die Eigentümerschaft abgeben. Das erreichen Sie über das Schlüsselwort __bridge_transfer. Der Cast (__bridge_transfer id)theImage wandelt das Bild in ein Objekt um und teilt dem ARC-Compiler mit, dass er die Verwaltung der Eigentümerschaft übernehmen soll.
Der Modifizierer __bridge_retained dient für den entgegengesetzten Fall, wenn Sie ein Objekt in ein Core-Foundation-Objekt umwandeln und der ARC-Compiler die Verwaltung der Eigentümerschaft dabei abgeben soll. Dieser Fall tritt beispielsweise bei Erzeugungs- und Kopierfunktionen auf:
CFStringRef CreateStringWithInteger(NSInteger inValue) {
NSString *theValue =
[[NSString alloc] initWithFormat:@"%d", inValue];
return (__bridge_retained CFStringRef)theValue;
}
Listing 6.107 Übergabe der Eigentümerschaft an Core Foundation
Durch das __bridge_retained erzeugt der ARC-Compiler nicht den Code für die Freigabe der Zeichenkette, auf die theValue verweist, und somit hält der Aufrufer der Funktion CreateStringWithInteger die Zeichenkette.
Sie können auch anders
Sie können statt __bridge_retained auch die Funktion CFBridgingRetain verwenden und den Cast in Listing 6.107 als (CFStringRef)CFBridgingRetain(theValue) schreiben. Auch für __bridge_transfer gibt es mit der Funktion CFBridgingRelease eine Alternative. Sie können den Cast beim Einfügen in das Array in Listing 6.60 also auch als CFBridgingRelease(theImage) schreiben.
Der Analyzer erkennt übrigens auch Speicherverwaltungsfehler, die durch falsche Modifizierer beim Toll-free Bridging entstehen. Sie können ihn über Product • Analyze starten, und er zeigt Ihnen mögliche Schwachstellen Ihres Codes an.
6.5.2C-Frameworks und ARC
Das Toll-free Bridging funktioniert sogar, wenn es für einen Typ keine entsprechende Klasse gibt oder umgekehrt. Dieser Fall tritt auch schon in Listing 6.60 auf; der Cast (__bridge_transfer id)theImage funktioniert, obwohl es keine Klasse (inklusive UIImage) in Cocoa Touch gibt, die dem Datentyp CGImage entspricht.
Dass der Cast dennoch funktioniert, liegt daran, dass auch viele Datentypen in den C-Frameworks sich in einer Typhierarchie mit einer gemeinsamen Menge von Funktionen befinden. Diese gemeinsamen Funktionen bilden dabei genau die Methoden ab, die eine Objective-C-Klasse implementieren muss, die das Protokoll NSObject implementiert.
Das bedeutet, dass Sie sowohl alle Referenzen aus Core Foundation als auch aus den anderen C-Frameworks (wie Core Graphics, ImageIO oder Address Book) zumindest wie Referenzen auf NSObject behandeln können. Beim manuellen Referenzzählen entspricht also beispielsweise die Anweisung CFRetain(theImage) der Anweisung [(id)theImage retain]. Diese transparente Abbildung der C-Datentypen auf Objective-C-Klassen hat nun auch den schönen Nebeneffekt, dass Sie, wie in Listing 6.60 gezeigt, Core-Graphics-Objekte in einem Foundation-Array sammeln können.
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.