アプリに WebKit WebView を埋め込むために、Racket Objective-C FFI を使用しています。
ページ読み込み通知を受け取るために、Racket で新しい ObjC クラスを作成しています。これは Web ビューのフレーム読み込みデリゲートとして設定されています。
クラスは次のようになります。
(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)))