Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Help with invoking a block
-
I am trying to implement a Pythonista API for WKWebView. All credit for all ObjC code so far goes to @mithrendal.
For the load policy decision, I would need to invoke the decision handler with a single integer parameter. Repurposing @JonB code from the multipeer project I arrived at the following, but get an exception stating that the handler was never called.
Any ideas? Thanks.
class _block_descriptor (Structure): _fields_ = [('reserved', c_ulong), ('size', c_ulong), ('copy_helper', c_void_p), ('dispose_helper', c_void_p), ('signature', c_char_p)] InvokeFuncType = ctypes.CFUNCTYPE(None, *[c_void_p, ctypes.c_int]) class _block_literal(Structure): _fields_ = [('isa', c_void_p), ('flags', c_int), ('reserved', c_int), ('invoke', InvokeFuncType), ('descriptor', _block_descriptor)] def webView_decidePolicyForNavigationAction_decisionHandler_(_self, _cmd, _webview, _navigation_action, _decision_handler): decision_handler = ObjCInstance(_decision_handler) retain_global(decision_handler) blk = _block_literal.from_address(_decision_handler) blk.invoke(decision_handler, 1)
-
IIRC block invoke functions take the block itself as an implicit first argument (basically likeNevermind,self
). So you probably need to add an extrac_void_p
in yourInvokeFuncType
's argument list, and addblk
as the first argument in yourblk.invoke
call.decision_handler
andblk
both refer to the block. -
This post is deleted! -
are you sure your callback is getting called? maybe an logging line to check. objc_util has trouble parsing type encodings for things like blocks, or complicated structures, so the protocol type encoding is probably getting munged, in which case, your method might not be getting created correctly.
Your block looks mostly okay -- you have the secret blk parameter, and the integer, though you might try c_void_p instead of None for restype.. i feel like i had to do that recently and couldnt explain why. You might also try c_long instead of c_int, as WKNavigationActionPolicy is defines as NSInteger, which an alias for c_long. if you run on 64 bit, there is a difference, though on 32 bit they are the same.
-
Looks like the callback is indeed not getting called, and that is likely because I missed the bit below. I am having a hard time finding the documentation about how these should be changed — I tried *3, and then also removing one @, but no luck.
f = webView_decidePolicyForNavigationAction_decisionHandler_ f.argtypes = [c_void_p]*4 f.restype = None f.encoding = b'v@:@@@@?'
-
the runction prototype (just searvh for method name in google, and choose the apple docs) is:
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
so, we have return type void, argtypes are 3 pointers, the last of which is a block. However, you also have the hidden self and selector args.
So encoding would be b'v@:@@@?'
argtypes would then be [c_void_p]*6 (though maybe 4.. i forget if the hidden args get added during the call.
Im not 100% sure about the last @?, you might try plain @. -
@JonB, thanks. Turns out my earlier attempt actually worked, but I did not notice it because of another error in the code.
So, to conclude, these were the right values, and the policy decision is working as expected:
f = webView_decidePolicyForNavigationAction_decisionHandler_ f.argtypes = [c_void_p]*3 f.restype = None f.encoding = b'v@:@@@?'
I also got to learn about the crazy fun argtype encoding values Apple uses.