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(TOCGenericImportTNSData 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.
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.
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.
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.
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(TCocoaGenericprivate
protected
function GetObjectiveCClass: PTypeInfo; override;
public
end;
...
function TViewController.GetObjectiveCClass: PTypeInfo;
begin
Result := TpyeInfo(ViewController);
end;
...
initialziation
TViewController.RegisterCocoa;