美文网首页
UIWebView 和 H5 交互的几个坑点

UIWebView 和 H5 交互的几个坑点

作者: 人话博客 | 来源:发表于2018-03-11 00:02 被阅读0次

UIWebView 和 H5 交互的几个坑点

当我们建立了 JSContext 和 UIWebView 之间的关系之后。
很自然的一个场景就是我们会把 OC 的方法(block) 注入到 JS 中,让 JS 来调用。

这里有个场景:在 HTML 中,有一个按钮,点击这个按钮会modal 出来一个控制器。
然后在打开的控制器里,也有个一 WebView,里面有个按钮,点击之后,需要关闭当前这个控制器。

效果图:

效果图

从第一个控制器打开第二个控制器的OC方法注入

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    // 获取 WebView 的 JS 执行环境
    _context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    _context.exceptionHandler = ^(JSContext *context, JSValue *exception) {
        NSLog(@"获取 UIWebView 的 JS 执行环境失败,原因: %@",exception.toString);
    };
    
    // 注入打开控制器的方法
    // self -> _context -> block -> self
    __weak typeof(self) weakSelf = self;
    _context[@"openVC"] = ^{
        NSLog(@"JS 调用 OC 方法的线程: %@",[NSThread currentThread]);
        __strong typeof(weakSelf) sself = weakSelf;
        UIViewController *vc = [[SecondController alloc] init];
        vc.view.backgroundColor = [UIColor orangeColor];
        /**
         his application is modifying the autolayout engine from a background thread after the engine was accessed from the main thread. This can lead to engine corruption and weird crashes.
         */
        // UI 操作要放到主线程。
        dispatch_async(dispatch_get_main_queue(), ^{
            [sself presentViewController:vc animated:YES completion:nil];
        });
    };
    
    NSLog(@"%@",@"OC 方法注入完成!");
}

上面那段代码遇到的坑点:

一、要注意循环引用。
其中 self --> jsContext -> block -> self

循环引用关系

解决方法也很简单:使用 weak - strong dance 打断 block 对 ViewController 的强引用。

二、OC 往 JS 中注入函数,这个函数在调用的时候,是在子线程执行的。

 JS 调用 OC 方法的线程: <NSThread: 0x618000073000>{number = 5, name = (null)}

所以,如果 JS 在调用 OC 的方法涉及到 UI 界面的操作的话,要记得回到主线程。

  // UI 操作要放到主线程。
        dispatch_async(dispatch_get_main_queue(), ^{
            [sself presentViewController:vc animated:YES completion:nil];
        });

JSValue & JSContext & Block 之间的引用关系

三者都是强引用。

主要包括在:

  1. JSValue 引用 JSContext 里面的 JS 对象和变量。而 JS 对象和变量依赖于 JSContext。所以JSValue 对 JSContext 是强引用。
  2. 我们往 JS 中注入 OC 函数的 block 时候,JSContext 会拉住这个 OC 的 block。所以 JSContext 也会强引住这个 block。
  3. 在 block 中访问 JSValue 。等于是 block 捕获了外部变量,这个本来没什么。block 经常性的会引用外部变量。但是由于,JSContext -> block , block -> JSValue , JSValue -> JSContext。 所以就产生了循环引用了。
  4. 在 block 中直接访问 JSContext 也会产生强引用关系。道理也很简单:JSContext -> block ,block -> JSContext。

下面分别有代码带解决这些强引用问题。

1.在 block 中,直接访问 JSValue 导致循环引用的问题。

在 block 中直接访问 JSValue 导致的循环引用

方法一:将 JSValue 作为参数传递到 Block 中。

 // JSValue -> JSContext
    JSValue *value = [JSValue valueWithObject:@{@"name" : @"lisi",@"age" : @22} inContext:_context];
    
    // JSContext -—> Block
    _context[@"ocFunc"] = ^(JSValue *value) {
        // Block -> JSValue
        // 解决办法,把 JSValue 当做参数传递到 block 中。
        NSLog(@"%@",value.toDictionary);
    };

方法二:使用 weak - strong dance

// JSValue 被 block 强引用,解决方式二。
    __weak typeof(value) weakValue = value;
    _context[@"ocFunc3"] = ^ {
        __strong typeof(weakValue) ssValue = weakValue;
        NSLog(@"weak - strong dance JSValue:%@",ssValue.toDictionary);
    };

2.在 block 中直接访问 JSContext 的循环引用问题

在 block 中直接访问 JSContext 导致的循环引用

解决方式一 : 使用 [JSContext currentContext] 来访问 JSContext。

_context[@"ocFunc2"] = ^{
        // 解决办法1:使用 [JSContext currentContext];
        [JSContext currentContext][@"doSomething"] = ^(NSString *something) {
            NSLog(@"something");
        };
}

解决方式二:使用 weak - strong dance 来解决

 // JSContext -> block
    __weak typeof(_context) weakContext = _context;
    _context[@"ocFunc2"] = ^{
              
        // 解决方法二,使用 weak-strong dance
        __strong typeof(weakContext) ssContext = weakContext;  
        ssContext[@"doSomething2"] = ^(NSString *someThing) {
            NSLog(@"%@",someThing);
        };
    };


最后总结:

  1. 由于 JSValue 指向的 JS 值依赖于 JSContext 上下文环境。所以 JSValue 天生的强引用了 JSContext。
  2. JSContext 注入 OC 的方法到 JS。JS 需要调用这个 OC 的 block。所以 JSContext 天生的会强引用这个 block。
  3. 在 block 中直接用捕获的方式使用 JSValue 导致循环引用是因为:JSValue 强引用了 JSContext。
  4. 在 block 中直接使用 JSContext,导致了循环引用就很普通了:两个对象都相互引用了对方

相关文章

网友评论

      本文标题:UIWebView 和 H5 交互的几个坑点

      本文链接:https://www.haomeiwen.com/subject/dzcifftx.html