Object Pascal has the concept of Forward declarations. Objective-C takes this concept a bit further: it allows to declare a class which is defined in another unit. This has been dubbed “Formal declaration” in Objective-Pascal. Looking at the syntax diagram, the following is a valid declaration:
MyExternalClass = objcclass external;
This is a formal declaration. It tells the compiler that MyExternalClass is an Objective-C class type, but that there is no declaration of the class members. The type can be used in the remainder of the unit, but its use is restricted to storage allocation (in a field or method parameter definition) and assignment (much like a pointer).
As soon as the class definition is encountered, the compiler can enforce type compatibility.
The following unit uses a formal declaration:
unit ContainerClass; {$mode objfpc} {$modeswitch objectivec1} interface type MyItemClass = objcclass external; MyContainerClass = objcclass private item: MyItemClass; public function getItem: MyItemClass; message 'getItem'; end; implementation function MyContainerClass.getItem: MyItemClass; begin result:=item; // Assignment is OK. end; end.
A second unit can contain the actual class declaration:
unit ItemClass; {$mode objfpc} {$modeswitch objectivec1} interface type MyItemClass = objcclass(NSObject) private content : longint; public function initWithContent(c: longint): MyItemClass; message 'initWithContent:'; function getContent: longint; message 'getContent'; end; implementation function MyItemClass.initWithContent(c: longint): MyItemClass; begin content:=c; result:=self; end; function MyItemClass.getContent: longint; begin result:=content; end; end.
If both units are used in a program, the compiler knows what the class is and can verify the correctness of some assignments:
Program test; {$mode objfpc} {$modeswitch objectivec1} uses ItemClass, ContainerClass; var c: MyContainerClass; l: longint; begin c:=MyContainerClass.alloc.init; l:=c.getItem.getContent; end.