JavaScriptCore - 将函数作为参数传递给ObjC

时间:2014-04-01 15:31:17

标签: javascript ios objective-c uiwebview javascriptcore

我有一个使用JavaScriptCore的UIWebView。我正试图从网页上调用一个ObjC函数。但是,函数需要异步调用,所以我传入一个在调用异步ObjC函数时调用的回调函数。

据我所知,JS函数通过桥接器等效于NSBlock。我目前的代码是:

context[@"currentUserLocation"] = ^( void(^callback)(NSString* str) )
{
    NSLog(@"Starting Async Function");

    //generic async function
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"delay complete");
        callback( @"return value" );
    });
};

我正在做的事情是否存在根本性的错误?从表面上看,ObjC似乎不知道运行回调函数的上下文。

1 个答案:

答案 0 :(得分:1)

我花了一点时间来解决这个问题。诀窍不是将回调参数视为块,而是将JSValue视为使用JSValue API调用它:

context[@"currentUserLocation"] = ^(JSValue *callback)
{
    NSLog(@"Starting Async Function");

    //generic async function
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"delay complete");
        //Check we actually have a callback (isObject is the best we can do, there is no isFunction)
        if ([callback isObject] != NO) {
            //Use window.setTimeout to schedule the callback to be run
            [context[@"setTimeout"] callWithArguments:@[callback, @0, @"return value"]];
        }
    });
};

在window.setTimeout()调用中包装回调允许JSVirtualMachine处理调度和线程,我发现如果回调完成任何UI工作,直接调用回调通常会导致死锁。