Racket Objective-C FFI - 避免重新定义课程

时间:2013-03-11 18:54:20

标签: racket

我正在使用Racket Objective-C FFI在应用程序中嵌入WebKit WebView。

为了接收页面加载通知,我在Racket中创建了一个新的ObjC类,它被设置为web-view的帧加载委托。

该课程类似于:

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

在DrRacket中运行代码时,它第一次运行良好。进一步的迭代导致过程死亡:

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
...

...这似乎表明它是ObjC类的重新定义的原因。

是否有一种干净的方式使用FFI或更一般的Racket功能,以避免重新定义类(如果它已经存在)?

我尝试在条件中包装define-objc-class,但它必须是顶级表单。

我可以下载到原始的ObjC运行时函数并动态定义委托类 - 但是避免这种情况会很好。


解决方案 - 将define-objc-class包装在let中,以在条件内的嵌套范围内定义类:

(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)))

2 个答案:

答案 0 :(得分:4)

我认为define-obj-class必须在顶级使用。但它是一个定义形式,因此您不能将其用作表达式。您应该可以执行以下操作:

(define MyClass
  (or ___ ;; find the class, if it already exists
      (let ()
        (define-objc-class MyClass ___)
        MyClass)))
顺便说一句,看起来修复崩溃的行为是在3月7日提交的。

答案 1 :(得分:1)