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