= Haskell Objective-C FFI: Objective-C Classes = == Declaring classes == Importing an ObjC class has two components: (1) we declare the class type, i.e., the Haskell type of objects of that class, and (2) we import the class object; i.e., the object on which we invoke class methods. {{{ foreign class objc "UIKit/UIKit.h UIView" C'UIView -- declares the class type foreign import objc "UIKit/UIKit.h UIView" o'UIView :: Class -- imports the class object }}} The class type is implemented as a newtype of a `ForeignPtr`. The type is abstract, but can be passed to and received from ObjC land; i.e., it is a ''foreign type'' in the sense of Section 3.2 of the Haskell FFI. The class object is looked up by the module initialisation code using `objc_getClass` and `Class` is defined in `Foreign.ObjectiveC` and corresponds to the type `Class` of the ObjC runtime. === Finaliser === A `foreign class` declaration can optionally specify a finaliser for the objects of the declared class. By default, the finaliser sends a `release` message to the finalised object. If a custom finaliser is specified, it needs to be implemented in ObjC (as per the requirements of `Foreign.ForeignPtr`). == Implementing ObjC classes in Haskell == Any ObjC class implemented in Haskell requires an `@interface` definition in a standard ObjC header file. Instead, of a `.m` file that contains the implementation, we provide the implementation in Haskell. In Haskell, we specify in the `foreign class` declaration that the curent Haskell module implements the class; thusly, {{{ foreign class objc "MyClass.h @implementation MyClass" MyClass }}} For any Haskell module that implements one or more class, we generate an ObjC stub file (not unlike the C stubs generated by GHC for foreign export wrappers in the C FFI). The stub file contains the actual class implementation. === Class and instance methods === For any class or instance method of a class implemented in Haskell, we have one `foreign export` statement; for example, {{{ foreign export objc "-[MyClass doSomethingCool:]" doSomethingCool :: MyClass -> UIView -> IO BOOL }}} ['''FIXME:''' ''Need to make sure that we can determine the ObjC signature from the Haskell signature in every case.''] ['''FIXME:''' ''Shouldn't that be "-[MyClass doSomethingCool:(UIView*)]"? Or will the types be filled in somehow?''] === Ivars and properties === Any ivars and properties of a class need to be defined in the header with the interface. We can import or export setters and getters of properties as any other selector. However, if the class is implemented in Haskell, we might want to have the ObjC compiler synthesize the setter and getter. We can achieve this via a `@synthesize` directive in the `foreign import` of the setter and getter. {{{ foreign import objc "@synthesize myProperty -[MyClass myProperty]" myProperty :: MyClass -> IO CInt foreign import objc "@synthesize myProperty -[MyClass setMyProperty:]" setMyProperty :: MyClass -> CInt -> IO () }}} The synthesize directive includes the property name, as the property declaration may have specified non-default names for the setter and getter. Moreover, the directive should be duplicated by specifying it in the setter and getter (except for a `readonly` property) – this is much like header file specifications are replicated across foreign declarations in the C FFI. We provide no special support to access the ivars directly beyond the functionality already available in the C FFI for Haskell. ''This approach is not valid for the non-fragile runtime used in 64-bit processes and on iOS.''