Nick Main
Nick Main

Reputation: 1450

Racket Objective-C FFI - avoid redefining a class

I am using the Racket Objective-C FFI to embed a WebKit WebView in an app.

In order to receive page-load notifications I am creating a new ObjC class in Racket that is set as the frame-load delegate of the web-view.

The class looks something like:

(define-objc-class MyWebFrameLoadDelegate NSObject
  []
  (- _void (webView: [_id wv] didFinishLoadForFrame: [_id wf])
    (send frame set-status-text "Page Loaded")))

When running the code within DrRacket it works great the first time. Further iterations cause the process to die:

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000020
...
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   libobjc.A.dylib                 0x00007fff8511e299 objc_registerClassPair + 63
1   Racket                          0x00000001002d329c ffi_call_unix64 + 76
2   Racket                          0x00000001002d3eb4 ffi_call + 644
3   Racket                          0x00000001002c612f ffi_do_call + 1599
4   ???                             0x00000001004b50cc 0 + 4299903180
...

... which seems to indicate that it is the re-definition of the ObjC class that is the cause.

Is there a clean way using the FFI, or more general Racket features, to avoid re-defining the class if it already exists ?

I tried wrapping define-objc-class in a conditional but it needs to be a top-level form.

I could drop down to the raw ObjC runtime functions and define the delegate class on the fly - but it would be nice to avoid that.


Solution - wrap the define-objc-class in a let to define the class in a nested scope inside a conditional:

(define MyWebFrameLoadDelegate
  (or (objc_lookUpClass "MyWebFrameLoadDelegate")
      (let ()
        (define-objc-class  MyWebFrameLoadDelegate NSObject
          []
          (- _void (webView: [_id wv] didFinishLoadForFrame: [_id wf])
             (send frame set-status-text "Page Loaded")))
        MyWebFrameLoadDelegate)))

Upvotes: 6

Views: 309

Answers (2)

soegaard
soegaard

Reputation: 31145

Just in case you missed it:

https://github.com/shekari/racket-webkit/blob/master/webkit.rkt

Enjoy,

Upvotes: 1

Ryan Culpepper
Ryan Culpepper

Reputation: 10663

I don't think define-obj-class must be used at top level. It is a definition form, though, so you can't use it as an expression. You should be able to do something like the following:

(define MyClass
  (or ___ ;; find the class, if it already exists
      (let ()
        (define-objc-class MyClass ___)
        MyClass)))

BTW, it looks like a fix for the crashing behavior was committed on March 7.

Upvotes: 4

Related Questions