Как проверить, что данное время WebView выполняет JS-код?

Это какао-компонент WebView. Например, он назвал JS-функцию:

[webView stringByEvaluatingJavaScriptFromString:@"foo"];

Мне нужно как-то подождать, пока эта функция будет выполнена, и начать делать другую работу. Как это можно сделать на Objective-C? Мне нужно что-то вроде:

[webView waitUntilJavaScriptCodeIsCompleted];

1 ответ

Решение

[webView stringByEvaluatingJavaScriptFromString:] выполняется синхронно и возвращает строку NSString результата выполнения переданного сценария. Итак, если вы просто хотите узнать, что скрипт выполнен, вызовите функцию, а когда он вернется, он запустится.

Однако, если вы говорите о скрипте с асинхронным выполнением, например XMLHTTPRequest или же setTimeoutтогда вам потребуется обратный вызов JavaScript в коде Objective-C, чтобы он знал, когда он закончится. Вот пример проекта, который делает именно это. Наиболее важные части находятся в AppDelegate:

#import "AppDelegate.h"
@import WebKit;
@import JavaScriptCore;

@interface AppDelegate ()

@property (weak) IBOutlet NSWindow *window;
@property (weak) IBOutlet WebView *webView;

@end

@interface AppDelegate (WebDelegate) <WebFrameLoadDelegate>
@end

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {

    JSGlobalContextRef jsGlobalContext = _webView.mainFrame.globalContext;

    // Add a function named "allDone" to the window object. It can be called from JavaScript like so:

    JSContext* context = [JSContext contextWithJSGlobalContextRef:jsGlobalContext];
    context[@"allDone"] = ^{
        NSLog(@"All Done was called");
    };

    context[@"jsLog"] = ^(NSString* message) {
        NSLog(@"JSLOG: %@", message);
    };


    _webView.frameLoadDelegate = self;

    NSURL* url = [NSURL URLWithString:@"https://example.com"];
    NSURLRequest *req = [[NSURLRequest alloc] initWithURL:url];
    [_webView.mainFrame loadRequest:req];
}

@end


@implementation AppDelegate (WebDelegate)

- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
    NSLog(@"Page loaded, calling JavaScript");

    // Script that logs a message, and then invokes allDone after 2 seconds.
    NSString* script =
        @"jsLog('Script running');"
        @"setTimeout(function() {\n"
            @"jsLog('javascript timer fired, invoking allDone...');\n"
            @"window.allDone();\n"
        @"}, 2000);";

    NSLog(@"Before stringByEvaluatingJavaScriptFromString");
    [_webView stringByEvaluatingJavaScriptFromString:script];
    NSLog(@"After stringByEvaluatingJavaScriptFromString");
}

@end

Что приводит к следующему выводу:

Page loaded, calling JavaScript
Before stringByEvaluatingJavaScriptFromString
JSLOG: Script running
After stringByEvaluatingJavaScriptFromString
JSLOG: javascript timer fired, invoking allDone...
All Done was called
Другие вопросы по тегам