From d7ebd49c9993a252f797595c1e13ab9d8390d5f5 Mon Sep 17 00:00:00 2001 From: Jacob Carlborg Date: Sun, 19 Jul 2015 12:42:46 +0200 Subject: [PATCH] Add documentation for interfacing with Objective-C --- doc.ddoc | 1 + objc_interface.dd | 369 ++++++++++++++++++++++++++++++++++++++++++++++ posix.mak | 4 +- spec.dd | 1 + win32.mak | 5 +- 5 files changed, 377 insertions(+), 3 deletions(-) create mode 100644 objc_interface.dd diff --git a/doc.ddoc b/doc.ddoc index 875ed4863d..15f9e30599 100644 --- a/doc.ddoc +++ b/doc.ddoc @@ -48,6 +48,7 @@ $(DIVID cssmenu, $(UL $(ROOT_DIR)ddoc.html, Embedded Documentation, $(ROOT_DIR)interfaceToC.html, Interfacing to C, $(ROOT_DIR)cpp_interface.html, Interfacing to C++, + $(ROOT_DIR)objc_interface.html, Interfacing to Objective-C, $(ROOT_DIR)portability.html, Portability Guide, $(ROOT_DIR)entity.html, Named Character Entities, $(ROOT_DIR)memory-safe-d.html, Memory Safety, diff --git a/objc_interface.dd b/objc_interface.dd new file mode 100644 index 0000000000..9a283198e4 --- /dev/null +++ b/objc_interface.dd @@ -0,0 +1,369 @@ +Ddoc + +$(SPEC_S Interfacing to Objective-C, + $(P + D has limited support for interfacing with Objective-C. It supports + external classes and calling instance methods. It is only available on + OS X, compiling for 64bit. + ) + + $(P + Fully working example is available at + $(LINK2 #usage-example, the bottom). + ) + + $(SECTION2 $(LNAME2 external-class, Declaring an External Class)) + + --- + extern (Objective-C) + interface NSString + { + const(char)* UTF8String() @selector("UTF8String"); + } + --- + + $(P + Currently all Objective-C classes need to be declared as interfaces in + D. All Objective-C classes that should be accessible from within D + need to be declared with the $(LINK2 #objc-linkage, Objective-C linkage). + ) + + $(P + The $(LINK2 #selector-attribute, `@selector`) attribute indicates which + Objective-C selector should be used when calling this method from D. + This attribute needs to be attached to all methods. + ) + + $(SECTION2 $(LNAME2 instance-method, Calling an Instance Method)) + + $(P + Calling an Objective-C instance method uses the same syntax as calling + regular D methods: + ) + + --- + const(char)* result = object.UTF8String(); + --- + + $(P + When the compiler sees a call to a method with Objective-C linkage it + will generate a call similar to how an Objective-C compiler would call + the method. + ) + + $(SECTION2 $(LNAME2 selector-attribute, The `@selector` Attribute)) + + $(P + The `@selector` attribute is a compiler recognized + $(LINK2 attribute.html#uda, UDA). It is used to tell the compiler which + selector to use when calling an Objective-C method. + ) + + $(P + Selectors in Objective-C can contain characters that are not valid in D + identifiers, `:`. D supports method overloading while Objective-C + achieves something similar by using different selectors. For these two + reasons it is better to be able to specify the selectors manually in D, + instead of trying to infer it. This allows to have a more natural names + for the methods in D. Example: + ) + + --- + extern (Objective-C) + interface NSString + { + NSString initWith(in char*) @selector("initWithUTF8String:"); + NSString initWith(NSString) @selector("initWithString:"); + } + --- + + $(P + Here the method `initWith` is overloaded with two versions, one + accepting `in char*`, the other one `NSString`. These two methods are + mapped to two different Objective-C selectors, `initWithUTF8String:` + and `initWithString:`. + ) + + $(P + The attribute is defined in druntime in + $(LINK2 phobos/core_attribute.html, `core.attribute`) and aliased in + $(LINK2 phobos/object.html, `object`), meaning it will be implicitly + imported. The attribute is only defined when the version identifier + $(LINK2 #objc-version-identifier, `D_ObjectiveC`) is enabled. + + ) + + $(SECTION3 $(LNAME2 compiler-checks, Compiler Checks)) + + $(P + The compiler performs the following checks to enforce the correct usage + of the `@selector` attribue: + ) + + $(UL + $(LI + The attribue can only be attached to methods with Objective-C + linkage + ) + + $(LI The attribue can only be attached once to a method) + $(LI The attribue cannot be attached to a template method) + + $(LI + The number of colons in the selector needs to match the number of + parameters the method is declared with + ) + ) + + $(P If any of the checks fail, a compile error will occur.) + + $(SECTION2 + $(LNAME2 objc-version-identifier, The `D_ObjectiveC` Version Identifier) + ) + + $(P + The `D_ObjectiveC` version identifier is a predefined version + identifier. It is enabled if Objective-C support is available for the + target. + ) + + $(SECTION2 $(LNAME2 objc-linkage, Objective-C Linkage)) + + $(P + Objective-C linkage is achieved by attaching the `extern (Objective-C)` + attribute to an interface. Example: + ) + + --- + extern (Objective-C) + interface NSObject + { + NSObject init() @selector("init"); + } + --- + + $(P + All methods inside an interface declared as `extern (Objective-C)` will + get implicit Objective-C linkage. + ) + + $(P + The linkage is recognized on all platforms but will issue a compile + error if it is used on a platform where Objective-C support is not + available. This allows to easily hide Objective-C declarations from + platforms where it is not available using the + $(LINK2 version.html#version, `version`) statement, without resorting to + string mixins or other workarounds. + ) + + $(SECTION2 $(LNAME2 memory-management, Memory Management)) + + $(P + The preferred way to do memory management in Objective-C is to use + Automatic Reference Counting, $(LINK2 https://developer.apple.com/library/mac/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html, ARC). + This is not supported in D, therefore manual memory management is + required to be used instead. This is achieved by calling $(LINK2 https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Protocols/NSObject_Protocol/index.html#//apple_ref/occ/intfm/NSObject/release, `release`) + on an Objective-C instance, like in the old days of Objective-C. + ) + + $(SECTION2 $(LNAME2 frameworks, Frameworks)) + + $(P + Most Objective-C code is bundled in something called a "Framework". + This is basically a regular directory, with the `.framework` extension + and a specific directory layout. A framework contains a dynamic + library, all public header files and any resources (images, sounds and + so on) required by the framework. + ) + + $(P + These directories are recognized by some tools, like the Objective-C + compiler and linker, to be frameworks. To link with a framework from + DMD, use the following flags: + ) + + --- + -L-framework -L + --- + + $(P + Where `` is the name of the framework to link with, without + the `.framework` extension. The two `-L` flags are required because the + linker expects a space between the `-framework` flag and the name of + the framework. DMD cannot handle this and will instead interpet the + name of the framework as a separate flag. + ) + + $(SECTION3 $(LNAME2 framework-paths, Framework Paths)) + + $(P + Using the above flag, the linker will search in the standard framework + paths. The standard search paths for frameworks are: + ) + + $(UL + $(LI `/System/Library/Frameworks`) + $(LI `/Library/Frameworks`) + ) + + $(P + The following flag from DMD can be used to add a new path in which to + search for frameworks: + ) + + --- + -L-F + --- + + $(P + For more information see the $(LINK2 https://developer.apple.com/library/ios/documentation/MacOSX/Conceptual/BPFrameworks/Tasks/IncludingFrameworks.html, reference documentation) + and the `ld` man page. + + ) + + $(SECTION2 $(LNAME2 usage-example, Full Usage Example)) + + $(P + Since the only parts of Objective-C that is currently supported is + calling instance methods, this example demonstrates how the Objective-C + runtime can be used to achieve a running example. + ) + + $(P + This example will create an Objective-C string, `NSString`, and log the + message using `NSLog` to stderr. + ) + + --- + extern (Objective-C) + interface Class + { + NSString alloc() @selector("alloc"); + } + --- + + $(P + This interface is used to emulate the $(LINK2 https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/#//apple_ref/c/tdef/Class, `Class`) + type available in the Objective-C runtime. The instance method `alloc` + will be used to emulate a class method in `NSObject`, + $(LINK2 https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/#//apple_ref/occ/clm/NSObject/alloc, alloc). + ) + + --- + extern (Objective-C) + interface NSString + { + NSString initWithUTF8String(in char* str) @selector("initWithUTF8String:"); + void release() @selector("release"); + } + --- + + $(P + This is a simplified declaration of the $(LINK2 https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/, `NSString`) + class. The $(LINK2 https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/#//apple_ref/occ/instm/NSString/initWithUTF8String:, `initWithUTF8String:`) + method will be used to convert a C string in UTF-8 to an Objective-C + string, `NSString`. The $(LINK2 https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Protocols/NSObject_Protocol/index.html#//apple_ref/occ/intfm/NSObject/release, `release`) + method is used to release an deallocate the string. Since D doesn't + support $(LINK2 https://developer.apple.com/library/mac/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html, ARC) + it's needed to manually release Objective-C instances. + ) + + --- + extern (C) Class objc_lookUpClass(in char* name) + --- + + $(P + The $(LINK2 https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/#//apple_ref/c/func/objc_lookUpClass, `objc_lookUpClass`) + function is used to get the class definition of the class with the + given name. + ) + + --- + extern (C) void NSLog(NSString, ...); + --- + + $(P + This $(LINK2 https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Functions/index.html#//apple_ref/c/func/NSLog, `NSLog`) + function prints a message to the System Log facility, i.e. to stderr + and Console. + ) + + --- + auto cls = objc_lookUpClass("NSString"); + --- + + $(P Get the class definition of `NSString`.) + + --- + auto str = cls.alloc(); + --- + + $(P Allocate an instance of the class, `NSString`.) + + --- + str = str.initWithUTF8String("Hello World!") + --- + + $(P Initialize the Objective-C string using a C string.) + + --- + NSLog(str); + --- + + $(P + Log the string to stderr, this will print something like this in the + terminal: + ) + + --- + 2015-07-18 13:14:27.978 main[11045:2934950] Hello World! + --- + + --- + str.release(); + --- + + $(P Release and deallocate the string.) + + $(P All steps combined look like this:) + + --- + module main; + + extern (Objective-C) + interface Class + { + NSString alloc() @selector("alloc"); + } + + extern (Objective-C) + interface NSString + { + NSString initWithUTF8String(in char* str) @selector("initWithUTF8String:"); + void release() @selector("release"); + } + + extern (C) void NSLog(NSString, ...); + extern (C) Class objc_lookUpClass(in char* name); + + void main() + { + auto cls = objc_lookUpClass("NSString"); + auto str = cls.alloc().initWithUTF8String("Hello World!"); + NSLog(str); + str.release(); + } + --- + + $(P + When compiling the application remember to link with the required + libraries, in this case the Foundation framework. Example: + ) + + --- + dmd -L-framework -LFoundation main.d + --- +) + +Macros: + TITLE=Interfacing to Objective-C diff --git a/posix.mak b/posix.mak index f370e32a66..b94f7e633e 100644 --- a/posix.mak +++ b/posix.mak @@ -150,8 +150,8 @@ SPEC_ROOT=spec intro lex grammar module declaration type property attribute prag expression statement arrays hash-map struct class interface enum \ const3 function operatoroverloading template template-mixin contracts \ version traits errors unittest garbage float iasm ddoc \ - interfaceToC cpp_interface portability entity memory-safe-d abi \ - simd + interfaceToC cpp_interface objc_interface portability entity memory-safe-d \ + abi simd SPEC_DD=$(addsuffix .dd,$(SPEC_ROOT)) CHANGELOG_FILES=$(basename $(subst _pre.dd,.dd,$(wildcard changelog/*.dd))) diff --git a/spec.dd b/spec.dd index 2a0aca396e..5368c9fc26 100644 --- a/spec.dd +++ b/spec.dd @@ -44,6 +44,7 @@ $(TOC Table of Contents, $(A ddoc.html, Embedded Documentation), $(A interfaceToC.html, Interfacing to C), $(A cpp_interface.html, Interfacing to C++), + $(A objc_interface.html, Interfacing to Objective-C), $(A portability.html, Portability Guide), $(A entity.html, Named Character Entities), $(A memory-safe-d.html, Memory Safety), diff --git a/win32.mak b/win32.mak index def7fc763a..0fa6336038 100644 --- a/win32.mak +++ b/win32.mak @@ -52,7 +52,7 @@ SPECSRC=spec.dd intro.dd lex.dd grammar.dd module.dd declaration.dd type.dd prop hash-map.dd struct.dd class.dd interface.dd enum.dd const3.dd \ function.dd operatoroverloading.dd template.dd template-mixin.dd \ contracts.dd version.dd traits.dd errors.dd unittest.dd garbage.dd \ - float.dd iasm.dd ddoc.dd interfaceToC.dd cpp_interface.dd \ + float.dd iasm.dd ddoc.dd interfaceToC.dd cpp_interface.dd objc_interface.dd \ portability.dd entity.dd memory-safe-d.dd abi.dd simd.dd DDOC=macros.ddoc html.ddoc dlang.org.ddoc windows.ddoc doc.ddoc $(NODATETIME) @@ -116,6 +116,7 @@ TARGETS=cpptod.html ctod.html pretod.html cppcontracts.html index.html overview. simd.html deprecate.html download.html 32-64-portability.html \ d-array-article.html dll-linux.html bugstats.php.html getstarted.html \ gpg_keys.html forum-template.html css/cssmenu.css ctarguments.html \ + objc_interface.html # exclude list MOD_EXCLUDES_RELEASE=--ex=gc. --ex=rt. --ex=core.internal. --ex=core.stdc.config --ex=core.sys. \ @@ -424,6 +425,8 @@ mixin.html : $(DDOC) mixin.dd module.html : $(DDOC) module.dd +objc_interface.html : $(DDOC) objc_interface.dd + operatoroverloading.html : $(DDOC) operatoroverloading.dd overview.html : $(DDOC) overview.dd