3. MAC APIs (POSIX, CORE und COCOA) in Delphi verwenden

Die MAC-Betriebsystem-Layer
Das MAC OS X Betriebssystem funktioniert im Wesentlichen mit 3 Layer-Systemen:

* POSIX
* CORE API
* COCOA Framework

Während die ersten beiden Layer über ein konventionelles C-Interface ansprechbar sind, ist das COCOA Layer über ein spezielles Objective-C Interface erreichbar. Eine Reihe von Funktionen steht letztlich in allen oder mehreren Schichten zur Verfügung.  Zum Beispiel können Sie den Computernamen mit einer POSIX-Funktion  (Gethostname) abfragen oder über das COCOA-Interface NSHost (Host.Name), wobei letzteres einer besonderen Aufruftechnik bedarf, aber dazu später.

POSIX

Die POSIX-Schnittstelle bietet typische Low-Level Betriebssystem-Funktionen an, die Sie auch in anderen Unix bzw. Linux-Systemen finden.
Wie bereits erwähnt, können Sie den Namen des Computers, auf dem Ihr Programm läuft, mit der Posix-Funktion „Gethostname“ abfragen. Diese Funktion ist in der „Posix.Unistd.pas“ definiert.

So ist nun die Funktion in der UniStdApi.inc implementiert:

function gethostname(name: MarshaledAString; namelen: size_t): Integer; cdecl; external libc name _PU + 'gethostname';
{$EXTERNALSYM gethostname}

Um diese für Delphi verwendbar zu machen, übernehmen wir diese wie folgt:

COREAPI
Die meisten der Core Apis finden Sie in der Unit Macapi.CoreFoundation.pas. Auch das Core API ist über eine C-Aufrufsystematik ansprechbar. Der wesentliche Unterschied zu den POSIX Funktionen ist der, dass hinter dem Core API sog. „reference counted objects“ stehen. D.h. es verbergen sich in Wahrheit Objekte hinter den Funktionen oder Datenstrukturen, manchmal sogar COCOA-Objekte. Wenn Sie hier also Strings als Übergabe-Parameter verwenden wollen, können dies nicht Delphi-Strings sein, sondern es müssen CFStrings sein, also reference counted String-Objekte.

Im Folgenden ein Beispiel, das die Verwendung der CFStrings demonstriert:

Hier wird die Core-Foundation Funktion „CFUserNotifiationDisplayAlert“ implementiert. Wir benutzen hier nur eine ganz einfache Implementierung, bei Bedarf kann die Alert-Funktion sogar noch mit einer TimeOut-Zeit angezeigt werden, mit einem weiteren Button und User-definierten Texten für den Schalter.

Die Funktion CFStringCreateWithCharacters erzeugt das String-Objekt. Alle Funktionen, deren Namen ein „Create“ oder ein „Copy“ enthalten, bewirken bei  deren Aufruf, dass der Referenzzähler für das Objekt um den Wert „1“ erhöht wird.  Nach der Verwendung der Objekte müssen Sie diese daher wieder mit der Funktion  „CFRelease“ freigeben, damit der Referenzzähler wieder um den Wert „1“ verringert  werden kann. Wenn Sie das nicht tun, behalten Sie Restobjekte im Speicher, die nach Beendigung Ihres Programms erhalten bleiben. Ich weiß nicht, inwiefern die  Programme für den MAC Appstore auf solche Mängel überprüft werden, ich rate hier vorbeugend zur sorgsamen Arbeit mit dem Umgang solcher Objekte.

Eine wichtige Ergänzung gilt in diesem Zusammenhang für Funktionen, die ein „Get“ im Namen haben. Dort werden Objekte nicht kopiert oder neu erzeugt, sondern Sie  verwenden quasi das Original. Hier müssen Sie nach der Get-Funktion direkt die  Funktion „CFRetain“ aufrufen, bevor Sie mit den String-Objekten weiterarbeiten. CFRetain führt dann ebenfalls eine Erhöhung des Referenzzählers durch und sichert  Ihnen sozusagen die weitere Verwendung des Objekts. Nach Beendigung der Arbeit  mit dem Objekt geben Sie es wieder mit „CFRelease“ frei, was den Referenzzähler  wieder um „1“ verringert.

COCOA API
Die API’s aus dem COCOA Framework sind speziell auf die Verwendung mit  Objective-C zugeschnitten. Viele Objekte und Funktionen finden Sie in der  Macapi.Foundation.pas implementiert.

Die COCOA „Objekte“ (Objetive-C Classes, Metaclasses und Protocols) sind i.d.R. als Interfaces implementiert. Für das NSString-Objekt/Klasse finden Sie daher direkt zwei Interface-Implementationen, einmal als

NSString = interface(NSObject)
und auch als
NSStringClass = interface(NSObjectClass).

Entsprechendes gilt z.B. für NSURL und NSURLCLASS. Das ist deswegen wichtig zu wissen, weil Sie manchmal Funktionen aus dem einen und aus dem anderen Interface benötigen werden. Übrigens ist hier vieles implementiert, aber auch nicht alles, hin und wieder wird es vorkommen, dass Sie einzelne Funktionen durch eine  Re-Implementierung selber nachrüsten müssen, wie ich das z.B. in der  HSW.FMXSandbox.pas unit gemacht habe.

Aber auch hier wollen wir uns ein Beispiel ansehen, wie COCOA-Objekte zu  verwenden sind, hier benutzen wir ein NSWorkspace-Objekt (die Unit  MacApi.Appkit.pas muss eingebunden sein). 

Mit diesem äußerst nützlichen COCOA Objekt können Sie auf dem MAC z.B. vom aktuellen Browser eine Internetseite anzeigen lassen.

Hier muss man die Wrap-Funktion verwenden, da die Delphi Objective C Bridge quasi nur "Raw" Objekte zurückliefert, die so nicht verwendbar sind. Zudem gilt für das Workspace-Objekt noch die Besonderheit, das je Programm nur ein shared Workspace Objekt zur Verfügung steht, auf das über die Funktion „sharedWorkspace“ zugegriffen werden muss.

Zwar sind auch die meisten COCOA Objekte reference counted, aber dies funktioniert i.d.R. automatisch, im Beispielsfall ist daher weder ein "Retain" noch ein "Release" für die oder nach der Verwendung des Objekts erforderlich.

Weitere Beispiele, zusätzliche Erläuterungstexte zu den technischen Zusammenhängen und nützliche Links in die Apple-Developer-Library zu Core Foundation bzw. COCOA Objekten finden Sie in der aktualisierten Version meines eBooks.

Also, was ist Ihre Meinung zur Verwendung der MAC-Apis unter Delphi, wie sind Ihre eigenen  Erfahrungen? Wenn Sie Anregungen zu Themen haben, lassen Sie es mich gerne wissen. Meine Mailadresse finden Sie oben auf der Seite unter dem Link "Anbieterkennzeichnung & Kontakt". Über meinen Hastasoft-Twitter Account werde ich posten, wenn neue Blogbeiträge zur Verfügung stehen. Wenn Sie wollen, klinken Sie sich dort ein (siehe meine Hastasoft-Seite).

Der nächste Blogbeitrag wird sich mit Grafikbearbeitung unter MAC OS X befassen und erläutern, was anders am TBitmap unter FireMonkey / MAC OS X ist und wie grundlegende Grafikfunktionen genutzt werden.

Viel Erfolg mit Delphi und FireMonkey!

Harry Stahl, 08.04.2013