Access to Objective-C classes in Delphi

Delphi represents all external Objective-C classes by interfaces. One interface is needed for Objective-C class methods and another for the instance methods.

For example, here is a declaration of NSData class located in Macapi.AppKit.pas:

NSDataClass = interface(NSObjectClass)

['{6B8C90E6-F881-47D9-8286-86139FAAACEB}']

...

{class} function dataWithBytes(bytes: Pointer; length: NSUInteger): Pointer; cdecl;

...

end;

NSData = interface(NSObject)

['{E2645613-B973-4F1C-93F1-950D9654506A}']

...

function initWithBytes(bytes: Pointer; length: NSUInteger): Pointer; cdecl;

...

end;

TNSData = class(TOCGenericImport) end;

TNSData is a helper class that allows to get access to Objective-C NSData class or instance.

Accesing to the class provided by OCClass method. When you create an instace of Objective-C class, you can access all instance method declared in NSData.

To create new isntace of Objective-C class you can use Alloc method of helper class.

var

Data1: NSData; // Objective-C Interface

Data2: NSData; // Objective-C Interface

begin

// Instantiate using Objective-C class

Data1 := TNSData.Wrap(TNSData.OCClass.dataWithBytes(...));

// Instatiate using Alloc method

Data2 := TNSData.Wrap(TNSData.Alloc.initWithBytes(...));

end;

Note: Both the initialization methods return an Objective-C object Id (not the Delphi interface that represents it).

The only way to get the Delphi interface is to call the helper class Wrap method. In some declaration you will get Delphi instance of Objective-C instance. You should remember, if a method returns Pointer it means that you should use Wrap method to create Delphi interface.

Memory management

All Objective-C instances managed by Objective-C runtime using reference counting are similar to Delphi interfaces.

Note: You should never destroy Objective-C instance by calling Delphi's destructor.

Write custom Objective-C class using TCocoaObject

Custom Objective-C objects are needed to implement Objective-C protocols or interfaces or when you need to subclass an existing Objective-C class.

The base class for it is TCocoaObject, which inherits from TOCLocal class, but has some additional features.

To declare custom Objective-C class you should declare new interface new class inherited from TCocoaObject (or TCocoaGeneric) class.

type

MyClass = interface(NSObject) // Declare super class of new custom Objective-C class

['{9F3CEE6F-ABFC-4B6B-892C-97C8C2575D6A}']

end;

TMyClass = class(TCocoaObject)

protected

function GetObjectiveCClass: PTypeInfo; override;

public

end;

...

function TMyClass.GetObjectiveCClass: PTypeInfo;

begin

Result := TpyeInfo(MyClass);

end;

...

initialziation

TMyClass.RegisterCocoa;

GetObjectiveCClass function returns the interface for the Objective-C object to be created.

In some cases Objective-C runtime create an instance automatically (for example ApplicationDelegate class) using class name. To allow this for custom Objective-C classes it should be registered by calling RegisterCocoa method in initialization section.

To create a new instance of cocoa object, just call the constructor. After this call, a new Objective-C instance will be created and RetainCount will be 1:

var

Obj: TMyObject;

...

Obj := TMyObject.Create;

...

Obj.Release;

...

To destroy this instance, just call TCocoaObject.Release method. It decreases the value of retainCount and if it becomes 0, the instance is automaticaly destoroyed. Do not call the destructor of the Objective-C instance, because it can still be referenced in Objective-C runtime.

Access to Objective-C id

If you need to post reference to your Objective-C instance to external API, you can use the following two methods:

1. If API requires Delphi interface, you should use TCocoaObject.Super property

2. If API requires Pointer, you should use TCocoaObject.CocoaPtr property.

TCocoaGeneric

If you want to access a superclass of Objective-C class, use TCocoaGeneric class instead of TCocoaObject. The difference of TCocoaGeneric from TCocoaObject is that Super property automatically returns Delphi interface of super class. The following example shows, that Super property of TViewController class is of UIViewController type. And you can directly access to super class method without any type casting.

type

ViewController = interface(UIViewController)

['{94B9D1EB-6758-4A4D-B46C-3DF0D224B600}']

end;

TViewController = class(TCocoaGeneric)

private

protected

function GetObjectiveCClass: PTypeInfo; override;

public

end;

...

function TViewController.GetObjectiveCClass: PTypeInfo;

begin

Result := TpyeInfo(ViewController);

end;

...

initialziation

TViewController.RegisterCocoa;

FAQ Docs Videos Samples About Us