首页 > 编程语言 >iOS开发笔记 - Objective-C和JavaScript的混编

iOS开发笔记 - Objective-C和JavaScript的混编

时间:2023-06-21 15:06:49浏览次数:54  
标签:JSContext context JavaScript iOS UIWebView Objective webView


最近看了一个对Github上面编程语言使用统计的排行榜,JavaScript真可以说是一枝独秀,很难想象20年前,这个语言只是浏览器中的装饰性语言,能做的事情也就是一点特效或者检查一下要提交给服务器的表单是否满足要求。今天的JavaScript已经是一个全栈语言,从客户端到服务器无所不在。很多编程语言都提供了跟JavaScript进行交互的接口,这一点在iOS开发中也不例外。
  iOS7以前,在App中调用JavaScript的方式只有一种,就是通过UIWebView对象的stringByEvaluatingJavaScriptFromString:方法。由于UIWebView中包含了CSS渲染引擎和JavaScript执行引擎(说白了就是微型一个浏览器),因此这个方法可以让UIWebView通过它的JavaScript运行时环境执行JavaScript代码,但是能做的事情非常有限,我们可以先看看下面的例子。

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    // 获得UIWebView中加载页面的标题
    NSString *title = [webView stringByEvaluatingJavaScriptFromString:
        @"document.title"];
    NSLog(@"%@", title);
    // 获得UIWebView中加载页面的链接地址
    NSString *urlStr = [webView stringByEvaluatingJavaScriptFromString:
        @"location.href"];
    NSLog(@"%@", urlStr);
}

  从iOS7开始,我们可以使用JavaScriptCore框架来让我们的Objective-C代码和JavaScript进行深度交互,简单的说我们可以在Objective-C代码中访问JavaScript中的变量或调用JavaScript的函数,也可以JavaScript中使用Objective-C的对象和方法。我们可以先看一个简单的例子。

先加入JavaScriptCore的头文件。

#import <JavaScriptCore/JavaScriptCore.h>

在Objective-C中使用JavaScript的正则表达式验证字符串。

// 创建JavaScript执行环境(上下文)
    JSContext *context = [[JSContext alloc] init];
    NSString *funCode =
        @"var isValidNumber = function(phone) {"
         "    var phonePattern = /^1[34578]\\d{9}$/;"
         "    return phone.match(phonePattern);"
         "};";
    // 执行上面的JavaScript代码
    [context evaluateScript:funCode];
    // 获得isValidNumber函数并传参调用
    JSValue *jsFunction = context[@"isValidNumber"];
    JSValue *value1 = [jsFunction callWithArguments:@[ @"13012345678" ]];
    NSLog(@"%@", [value1 toBool]? @"有效": @"无效");    // 有效
    JSValue *value2 = [jsFunction callWithArguments:@[ @"12345678899" ]];
    NSLog(@"%@", [value2 toBool]? @"有效": @"无效");    // 无效

在Objective-C中调用JavaScript函数求阶乘。

// 创建JavaScript执行环境(上下文)
    JSContext *context = [[JSContext alloc] init];
    // 可以将一个block传给JavaScript上下文
    // 它会被转换成一个JavaScript中的函数
    context[@"factorial"] = ^(int x) {
        double result = 1.0;
        for (; x > 1; x--) {
            result *= x;
        }
        return result;
    };
    // 执行求阶乘的函数
    [context evaluateScript:@"var num = factorial(5);"];
    JSValue *num = context[@"num"];
    NSLog(@"5! = %@", num);    // 5! = 120

  JavaScript和Objective-C中类型的对应关系如下表所示:

Objective-C类型

JavaScript类型

nil

undefined

NSNull

null

NSString

string

NSNumber

number, boolean

NSDictionary

Object object

NSArray

Array object

NSDate

Date object

NSBlock

Function object

id

Wrapper object

Class

Constructor object

  
  再来看一个例子。我们在根视图控制器中放置一个按钮,点击后会导航到下一个视图控制器,其中有一个UIWebView加载了一个网页,页面中有一颗按钮,我们希望点击按钮后导航到上一个视图控制器,要做到这一点,就需要在JavaScript中访问Objective-C对象和方法。

页面的代码:

<!doctype html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>测试页面</title>
        <style type="text/css">
            #backButton { 
                display: inline-block;
                width:50px; height:30px;
            }
        </style>
    </head>

    <body>
        <button id="backButton">返回</button>
        <script type="text/javascript">
            var btn = document.getElementById("backButton");
            var cb = function() {
                window.alert('Hello');
            };
            btn.addEventListener('click', cb, false);
        </script>
    </body>
</html>

第二个视图控制器的代码:

#import "ViewController.h"
#import <JavaScriptCore/JavaScriptCore.h>

@protocol MyProtocol <JSExport>

- (void) letsGoBack;

@end

@interface SecondViewController : ViewController <MyProtocol>

@end
@interface SecondViewController () <UIWebViewDelegate>

@property (weak, nonatomic) IBOutlet UIWebView *myWebViw;

@end

@implementation SecondViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    [_myWebViw loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:
        @"http://localhost:8080/myweb/test.html"]]];
    _myWebViw.delegate = self;
}

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    // 通过UIWebView获得网页中的JavaScript执行环境
    JSContext *context = [webView valueForKeyPath:
        @"documentView.webView.mainFrame.javaScriptContext"];
    // 设置处理异常的block回调
    [context setExceptionHandler:^(JSContext *ctx, JSValue *value) {
        NSLog(@"error: %@", value);
    }];

    context[@"callBackObj"] = self;
    // 下面的代码移除了按钮原先绑定的事件回调重新绑定返回上一个视图控制器的代码
    NSString *code =
                   @"var btn = document.getElementById('backButton');"
                    "btn.removeEventListener('click', cb);"
                    "btn.addEventListener('click', function() {"
                    "   callBackObj.letsGoBack();"
                    "});";
    [context evaluateScript:code];
}

// 实现协议中的方法
- (void) letsGoBack {
    // 必须回到主线程刷新用户界面
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.navigationController popViewControllerAnimated:YES];
    });
}

@end

  可以在Github上下载到上面例子的完整代码。


标签:JSContext,context,JavaScript,iOS,UIWebView,Objective,webView
From: https://blog.51cto.com/u_16166070/6528502

相关文章

  • iOS开发笔记 - 语言篇之Swift
     2014年的苹果全球开发者大会(WWDC),当CraigFederighi向全世界宣布“Wehavenewprogramminglanguage”(我们有了新的编程语言)的时候,全场响起了最热烈和持久的掌声,伴随着掌声到来的语言叫Swift。接下来CraigFederighi更是毫不掩饰的告诉大家,Swift将成为主宰iOS和Mac开发的新语言,甚......
  • javascript WebUploader 分块上传
    ​ 前言文件上传是一个老生常谈的话题了,在文件相对比较小的情况下,可以直接把文件转化为字节流上传到服务器,但在文件比较大的情况下,用普通的方式进行上传,这可不是一个好的办法,毕竟很少有人会忍受,当文件上传到一半中断后,继续上传却只能重头开始上传,这种让人不爽的体验。那有没有......
  • JavaScript异步编程:异步的数据收集方法
    我们先尝试在不借助任何工具函数的情况下来解决这个问题。笔者能想到的最简单的方法是:因前一个readFile的回调运行下一个readFile,同时跟踪记录迄今已触发的回调次数,并最终显示输出。下面是笔者的实现结果。Asyncjs/seriesByHand.jsvarfs=require('fs');process.chdir('recipes'......
  • JavaScript版本的策略模式
    俗话说,条条大路通罗马。在美剧《越狱》中,主角MichaelScofield就设计了两条越狱的道路。这两条道路都可以到达靠近监狱外墙的医务室。同样,在现实中,很多时候也有多种途径到达同一个目的地。比如我们要去某个地方旅游,可以根据具体的实际情况来选择出行的线路。如果没有时间但是不在乎......
  • JavaScript王国里的鸭子合唱团
    编程语言按照数据类型大体可以分为两类,一类是静态类型语言,另一类是动态类型语言。静态类型语言在编译时便已确定变量的类型,而动态类型语言的变量类型要到程序运行的时候,待变量被赋予某个值之后,才会具有某种类型。静态类型语言的优点首先是在编译时就能发现类型不匹配的错误,编辑......
  • axios
    Axios对原生的AJAX进行封装,简化书写。Axios官网是:​https://www.axios-http.cn​1.基本使用axios使用是比较简单的,分为以下两步:引入axios的js文件<scriptsrc="js/axios-0.18.0.js"></script>使用axios发送请求,并获取响应结果发送get请求axios({  m......
  • 10个具体项目生动精彩讲述JavaScript;超级Web应用,构建不再困难
     “JavaScript,就是那种小时候长得很丑,长大了却谁都想要的孩子。”诞生初期,由于很多所谓的“资深”程序员的滥用,让这个孩子饱受质疑,直到前几年DOM技术开始崛起,JavaScript才逐渐恢复了曾经的兴盛。并且,这时的JavaScript更多了一份成熟,少了一缕稚气。JavaScript虽然已经被当......
  • 全面解读Objective-C语言及Cocoa特性——《Objective-C基础教程》
    媒体评论“这是我读过的最好的一本编程书。我从头到尾逐字逐句地读完了它,可读性真强啊!试问,现在有几本技术书能达到这种程度?”——Amazon读者评论“这本书结构清晰,逻辑性强,风格幽默……借助本书,你可以毫不费力地从一个初学者摇身一变升级为优秀的Objective-C编程人员。”——Ama......
  • iPhone开发四剑客之《Objective-C基础教程》
     iPhone开发四剑客之《Objective-CObjective-C语言是C语言的一个扩展集,许多(可能是大多数)具备MacOSX外观的应用程序都是使用该语言开发的。它以C语言为基础,添加了一些微妙但意义重大的特性。苹果公司为Objective-C语言提供了Cocoa工具包。Cocoa是使用Objective-C......
  • 活学活用流行的JavaScript库——《JavaScript实战》
    媒体评论“本书并不像一本教材,畅读之后,你会觉得它就是一位讲课生动的老师,带领你遨游JavaScript海洋,把你推向技术风浪的前沿,同时又给了你一个功能完备的冲浪板,接下来就是你在风口浪尖上享受JavaScript高潮的时候了。”                  ......