6

アプリに 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-classlet条件内のネストされたスコープでクラスを定義します。

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

2 に答える 2

4

define-obj-classトップレベルで使用する必要はないと思います。ただし、これは定義形式であるため、式として使用することはできません。次のようなことができるはずです。

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

ところで、クラッシュ動作の修正は3月7日にコミットされたようです。

于 2013-03-11T20:28:14.640 に答える
1

あなたがそれを逃した場合に備えて:

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

楽しみ、

于 2013-03-11T21:46:55.820 に答える