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

1 ответ

Решение

Мне понадобилось немного времени, чтобы освоить это. Хитрость заключается не в том, чтобы рассматривать аргумент обратного вызова как блок, а в JSValue, а затем вызывать его с помощью API JSValue:

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

Другие вопросы по тегам