Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Racket Objective-C FFI - avoid redefining a class

Tags:

racket

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)))
like image 550
Nick Main Avatar asked Mar 11 '13 18:03

Nick Main


People also ask

What is FFI/unsafe in racket?

The ffi/unsafe library enables the direct use of C-based APIs within Racket programs— without writing any new C code. From the Racket perspective, functions and data with a C-based API are foreign, hence the term foreign interface.

What is foreign interface in racket?

From the Racket perspective, functions and data with a C-based API are foreign, hence the term foreign interface. Furthermore, since most APIs consist mostly of functions, the foreign interface is sometimes called a foreign function interface, abbreviated FFI.

What is a class interface in Objective C?

In Objective-C, the class interface specifies exactly how a given type of object is intended to be used by other objects. In other words, it defines the public interface between instances of the class and the outside world.

What is foreign function interface (FFI)?

Furthermore, since most APIs consist mostly of functions, the foreign interface is sometimes called a foreign function interface, abbreviated FFI.


2 Answers

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.

like image 95
Ryan Culpepper Avatar answered Sep 28 '22 04:09

Ryan Culpepper


Just in case you missed it:

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

Enjoy,

like image 25
soegaard Avatar answered Sep 28 '22 02:09

soegaard