[Openmcl-devel] How to access Cocoa objects returned via indirect references (i.e. NSError)
Gary Byers
gb at clozure.com
Mon Jul 24 23:14:41 PDT 2006
On Tue, 25 Jul 2006, Phil wrote:
>
> On Jul 24, 2006, at 11:35 PM, Gary Byers wrote:
>
>>
>> I'm not sure that I understand the question,
>
> You caught the essence of my question despite my poor wording.
>
>>
>> Note that if something's returned by reference, you'd generally
>> do something like:
>>
>> (let* ((ns-error-ptr :id))
Of course, if I'd been paying more attention, I'd have used RLET instead
of LET*.
>> (send some-message ... ns-error-ptr ...)
>> (let* ((the-ns-error (pref ns-error-ptr :id)))
>> ;; At this point, THE-NS-ERROR should be an NSError (or possibly
>> ;; a NULL pointer if there was no error ...
>> ...)))
>>
>> (That's no different from how other things are returned by reference.)
>>
>
> That is what I was struggling with and mostly solved my problem. The
> first let with (ns-error-ptr :id) resulted in an error (The value :ID
> is not of the expected type MACPTR) in the send some-message. Here's
> the relevant snippet:
>
> (ccl::with-autorelease-pool
> (let* ((error-ptr (ccl::make-objc-instance 'ns-error)) ; :id
> results in error
> (the-xml (ccl::make-objc-instance 'ns-xml-document
>
> :init-with-contents-of-url (ccl::send (ccl::@class ns-url)
>
> :url-
> with-string #@"http://blah")
>
> :options (logior #$NSXMLNodePreserveWhitespace
>
> #$NSXMLNodePreserveCDATA)
>
> :error error-ptr)))
> (if error-ptr
> (let ((the-error (ccl::pref error-ptr :id)))
> (format t "An error was encountered: ~a~%" the-error)))
> the-xml))
>
(ccl::with-autorelease-pool
;; First, we (stack) allocate a pointer to a pointer to an
;; NSObject (something of foreign type :id).
(rlet ((error-ptr :id))
;; At this point, the value of ERRROR-PTR is well-defined (it's
;; an address on a stack, and if we run this in the same thread
;; and in the same execution context, it'll always be pointing
;; to the same address.)
;; Since we haven't done anything to initialize the word of
;; memory that ERROR-PTR points to, the result of doing
;; (pref error-ptr :id) at this point is a little less deterministic;
;; the value is "whatever (garbage) was in that stack location".
;; We don't care; all that we've done is to reserve a word of
;; memory. We'll pass the address of that word to an ObjC method,
;; and it may store the address of some (constant or other) NSError
;; object there.
;;
;; On second thought, let's be defensive and store a NULL pointer
;; there.
;;
(setf (pref error-ptr :id) (%null-ptr))
(let* ((the-url-object
(send (@class "NSURL")
:url-with-string #@"http:/blah"))
(the-xml-document
(make-objc-instance 'ns:ns-xml-document
:with-contents-of-url the-url-object
:options (logior #$NSXMLNodePreserveWhitespace
#$NSXMLNodePreserveCDATA)
:error error-ptr)))
;; Were we able to create an NSXMLDocument ?
(if (%null-ptr-p the-xml-document)
(error "Error creating NSXMLDocument, NSError = ~s"
(pref error-ptr :id))
the-xml-document))))
The above is untested code; I'm working on something else at the moment
and can't easily test it (the only machine that I have free is running
10.3.9); I think that that's the general idea, however, and barring
typos or other brain damage it should work fine.
It's hard to know just by looking at a C/ObjC function prototype
whether something passed by reference is an input, output, or both.
In the case of this message, the parameter associated with the
:error component of the messagee is something returned by the message,
so the caller needs to reserve space into which the callee can store
that extra return value.
Actually, I was able to get that to work (so just beware of the fact
that the code above neglects to use ccl:: prefixes where it should ...),
and running it produced:
> Error: Error creating NSXMLDocument, NSError = #<NS-ERROR NSError "zero byte resource" Domain=NSURLErrorDomain Code=-1014 UserInfo={
> NSErrorFailingURLKey = http:/blah;
> NSErrorFailingURLStringKey = "http:/blah";
> NSLocalizedDescription = "zero byte resource";
> } (#x38A900)>
which (I assume) is a complaint about the bogus NSURL.
More information about the Openmcl-devel
mailing list