我正在使用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")))
Run Code Online (Sandbox Code Playgroud)
在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
...
Run Code Online (Sandbox Code Playgroud)
...这似乎表明它是ObjC类的重新定义的原因.
是否有一种干净的方式使用FFI或更一般的Racket功能,以避免重新定义类(如果它已经存在)?
我尝试define-objc-class用条件包装,但它需要是一个顶级形式.
我可以下载到原始的ObjC运行时函数并动态定义委托类 - 但是避免这样做会很好.
解决方案 - 将define-objc-classa 包装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)))
Run Code Online (Sandbox Code Playgroud)
我认为不必define-obj-class在顶层使用。不过,它是一种定义形式,因此您不能将其用作表达式。您应该能够执行以下操作:
(define MyClass
(or ___ ;; find the class, if it already exists
(let ()
(define-objc-class MyClass ___)
MyClass)))
Run Code Online (Sandbox Code Playgroud)
顺便说一句,看起来崩溃行为的修复已于 3 月 7 日修复。