| | 1 | Here are a bunch of conversions between Obj-C code and the equivalent Clozure CL Cocoa |
| | 2 | Bridge code, to show how different idioms are encoded. Some of these things are part of |
| | 3 | the Clozure CL FFI, and not specific to the bridge, but they are included here to give |
| | 4 | an overall view. |
| | 5 | |
| | 6 | == literals == |
| | 7 | |
| | 8 | T and NIL are mapped to the boolean values YES and NO, respectively. All numbers are |
| | 9 | also portable. NSStrings need to be explicitly created: |
| | 10 | |
| | 11 | {{{ |
| | 12 | @"some string" |
| | 13 | }}} |
| | 14 | |
| | 15 | becomes |
| | 16 | |
| | 17 | {{{ |
| | 18 | #@"some string" |
| | 19 | }}} |
| | 20 | |
| | 21 | If you need to convert between lisp strings and NSStrings, the following functions are |
| | 22 | what you want. |
| | 23 | |
| | 24 | {{{ |
| | 25 | (let ((a-lisp-string "foo")) |
| | 26 | (ccl::%make-nsstring a-lisp-string)) |
| | 27 | }}} |
| | 28 | |
| | 29 | and you also need to convert NSStrings when you receive them: |
| | 30 | |
| | 31 | {{{ |
| | 32 | (ccl::lisp-string-from-nsstring (#/title some-object)) |
| | 33 | }}} |
| | 34 | |
| | 35 | Clozure CL used to autoconvert strings, but that caused issues with memory management. |
| | 36 | So make sure to retain/release any NSStrings you need to. |
| | 37 | |
| | 38 | {{{ |
| | 39 | nil |
| | 40 | NULL |
| | 41 | }}} |
| | 42 | |
| | 43 | Both of these are null pointers. Use |
| | 44 | |
| | 45 | {{{ |
| | 46 | ccl:+null-ptr+ |
| | 47 | }}} |
| | 48 | |
| | 49 | to represent them in Lisp. |
| | 50 | |
| | 51 | === types === |
| | 52 | |
| | 53 | You may have to use type (not class) names as the return values of methods you define |
| | 54 | and in some other cases. |
| | 55 | |
| | 56 | {{{ |
| | 57 | NSInteger |
| | 58 | BOOL |
| | 59 | }}} |
| | 60 | |
| | 61 | becomes |
| | 62 | |
| | 63 | {{{ |
| | 64 | #>NSInteger |
| | 65 | #>BOOL |
| | 66 | }}} |
| | 67 | |
| | 68 | == constants, enumerations and variables == |
| | 69 | |
| | 70 | {{{ |
| | 71 | NSTitledWindowMask |
| | 72 | NSUTF8StringEncoding |
| | 73 | }}} |
| | 74 | |
| | 75 | {{{ |
| | 76 | #$NSTitledWindowMask |
| | 77 | #$NSUTF8StringEncoding |
| | 78 | }}} |
| | 79 | |
| | 80 | == selectors == |
| | 81 | |
| | 82 | {{{ |
| | 83 | @selector(someSelector:withParams:) |
| | 84 | }}} |
| | 85 | |
| | 86 | becomes |
| | 87 | |
| | 88 | {{{ |
| | 89 | (@selector "someSelector:withParams:") |
| | 90 | }}} |
| | 91 | |
| | 92 | == class definition == |
| | 93 | |
| | 94 | {{{ |
| | 95 | @interface SomeClass : SuperClass { |
| | 96 | IBOutlet NSString *aString; |
| | 97 | } |
| | 98 | }}} |
| | 99 | |
| | 100 | {{{ |
| | 101 | (defclass some-class (super-class) |
| | 102 | ((a-string :foreign-type :id)) |
| | 103 | (:metaclass ns:+ns-object)) |
| | 104 | }}} |
| | 105 | |
| | 106 | == method definition == |
| | 107 | |
| | 108 | {{{ |
| | 109 | @implementation SomeClass // just included so we show the class name |
| | 110 | |
| | 111 | - (id) initWithFrame:(NSRect)frame andStuff:(id)stuff { |
| | 112 | if ((self = [super initWithFrame:frame])) { |
| | 113 | // body |
| | 114 | } |
| | 115 | return self; |
| | 116 | } |
| | 117 | |
| | 118 | - (void) viewDidAppear:(BOOL)animated { |
| | 119 | [super viewDidAppear:animated]; |
| | 120 | // body |
| | 121 | } |
| | 122 | }}} |
| | 123 | |
| | 124 | {{{ |
| | 125 | (objc:defmethod (#/initWithFrame:andStuff: :id) |
| | 126 | ((self some-class) (frame #>NSRect) (stuff :id)) |
| | 127 | (let ((new-self (#/initWithFrame: self frame))) |
| | 128 | (when new-self |
| | 129 | ;; body |
| | 130 | ) |
| | 131 | new-self)) |
| | 132 | |
| | 133 | (objc:defmethod (#/viewDidAppear: :void) ((self some-class) (animated #>BOOL)) |
| | 134 | (call-next-method)) |
| | 135 | ;; body |
| | 136 | ) |
| | 137 | }}} |
| | 138 | |
| | 139 | There is the usual CALL-NEXT-METHOD (which works just as expected in Obj-C |
| | 140 | methods), but that doesn’t cover all the use cases you need in Obj-C. As in common in init methods, you sometimes |
| | 141 | need to call a super-method with a different name than the current method. This is |
| | 142 | where CALL-NEXT-METHOD breaks down. The easiest way to handle this yourself is to treat the call to super as a call to self, as in the above example. |
| | 143 | |
| | 144 | == instantiating objects == |
| | 145 | |
| | 146 | {{{ |
| | 147 | [[NSWindow alloc] initWithContentRect:NSRectMake(0, 0, 300, 300) |
| | 148 | styleMask:NSTitledWindowMask |
| | 149 | backing:NSBackingStoreBuffered |
| | 150 | defer:YES]; |
| | 151 | }}} |
| | 152 | |
| | 153 | {{{ |
| | 154 | (make-instance 'ns:ns-window |
| | 155 | :with-content-rect (ns:make-ns-rect 0 0 300 300) |
| | 156 | :style-mask #$NSTitledWindowMask |
| | 157 | :backing #$NSBackingStoreBuffered |
| | 158 | :defer t) |
| | 159 | }}} |
| | 160 | |
| | 161 | == method call == |
| | 162 | |
| | 163 | {{{ |
| | 164 | [self doSomethingToObject:anObject]; |
| | 165 | [NSDate date]; |
| | 166 | }}} |
| | 167 | |
| | 168 | {{{ |
| | 169 | (#/doSomethingToObject: self an-object) |
| | 170 | (#/date ns:ns-date) |
| | 171 | }}} |
| | 172 | |
| | 173 | == calling setters / setting properties == |
| | 174 | |
| | 175 | You can call setters the same way as any other method, of course, but to make them work |
| | 176 | more like properties or slots, you can also use SETF for them. |
| | 177 | |
| | 178 | {{{ |
| | 179 | [self setName:aName]; |
| | 180 | self.name = aName; // provided there is a @property defined |
| | 181 | }}} |
| | 182 | |
| | 183 | {{{ |
| | 184 | (#/setName: self aName) |
| | 185 | }}} |
| | 186 | |
| | 187 | or |
| | 188 | |
| | 189 | {{{ |
| | 190 | (setf (#/name self) a-name) |
| | 191 | }}} |
| | 192 | |
| | 193 | The SETF form will work regardless of whether there's a property defined, but a getter |
| | 194 | (IE (#/name self)) must exist. This is because users of SETF expect the stored value to |
| | 195 | be returned, but Cocoa setters generally have no return value. |