JavaScriptCore Передача функции в качестве параметра в ObjC

У меня есть UIWebView, который использует JavaScriptCore. Я пытаюсь вызвать функцию 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 не будет знать, в каком контексте запускать функцию обратного вызова.


person TMacGyver    schedule 01.04.2014    source источник


Ответы (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 позаботиться о планировании и многопоточности. Я обнаружил, что вызов обратного вызова напрямую часто приводит к взаимоблокировкам, если обратным вызовом выполняется какая-либо работа с пользовательским интерфейсом.

person erm410    schedule 12.04.2014
comment
В итоге я передал имя функции в виде строки, но этот ответ определенно намного лучше, обязательно попробуйте. - person TMacGyver; 13.04.2014
comment
Вы можете посмотреть на этот вопрос? stackoverflow.com/questions/23047512 / - person TMacGyver; 13.04.2014