Wax Lua 使用方法

说一下 Wax 的特点,它支持你在脚本里使用任何 OC 的类,同样也支持你创建一个类。

使用一个类时你会这样使用:

1
2
NSString -- Returns the NSString class
UIView -- Returns the UIView class

这样调用其实一个语法糖,实际上他调用的是wax.class[“UIView “],但是我们在使用的时候不需要知道这些,因为在这个框架里已经通过设置元表的方法实现了这一点。

当定义一个类的时候会是这样:

1
waxClass{"MyClass", NSObject}

遵循协议的类:

1
waxClass{"MyClass",NSObject,protocols={"UITableViewDelegate","UITableViewDataSource"}}

在你定义这个类的脚本文件里缩写的其他function都将作为这个类的实例方法。且这个方法的第一个参数必须是 self ,这就是Wax模仿Objective-C的面向对象的关键所在。 因此在Wax中调用方法要使用冒号,类似这样:

1
UIApplication:sharedApplication()

其实他就等同于这样:

1
UIApplication.sharedApplication(UIApplication)

在调用含有多个参数的方法时候,使用 _ 来代替OC中的:,例如:

1
[UIAlertView initWithTitle:@"title" message:@"message" delegate:nil];  //OC方式
1
UIAlertView:initWithTitle_message_delegate("title", "message", nil)    --Wax 方式

使用 Wax 创建对象不需要你 alloc ,因为他会帮你实现内存管理,它是怎么实现的稍后再说。

Wax 不支持属性Property,因此你不能使用OC中的点语法, Wax 要求Lua与OC的通信必须通过方法来完成,就是如果你要访问一个Property的话就只能使用它的setter 和 getter 方法。 如果你在脚本中使用了点语法,那么你将为这个对象创建一个实例变量,但这只是在Lua层面的,在OC层面它并不知道你创建了这样一个实例变量。

Wax 会强制的把OC的对象转换成Lua的对象,同时他也支持反向转化,比如一个方法需要 NSString 类型的参数,你可以直接传递Lua的字符串进去。 有时你不想让OC对象被强制转化成Lua的,它也提供了相应变回OC对象的方法。

Wax 对枚举和结构的支持并不是很好,就是它需要把你需要用到的枚举和结构都按照他定义好的格式添加到 APP_ROOT/wax/stdlib/enums.lua和APP_ROOT/wax/wax-scripts/structs.lua 中,只有这样你才能正常的使用它们。

Wax 对协议的支持也不是很好,有的协议在 Wax 中可以正常使用,有的则不可以,你在源文件中会看到ProtocolLoader.h这样一个文件,他需要把不支持的协议预先加载到runtime中,作者自己也不知道这是为什么,也许是一个他不知道的runtime method。

Wax 也是不支持分类的,不过这个使用的比较少,不支持也没有什么。

Wax Lua 实现原理

我们知道OC是一门动态语言,他的 runtime 很强大,强大到你可以在运行时动态的创建一个类,而 Wax 真是借助于OC的 runtime 实现了它一系列的功能。 目前我们在使用的 CCLuaObjcBridge ,这个类也是实现了Lua调用OC的方法,他借助的也是 runtime ,但是跟 Wax 比起来,他就简单了很多,从他的限制就能看出来,它只支持类的静态方法,方法只能有一个参数,不能创建对象,不能调用实例方法。它的实现是这样的:通过类名找到类对象,通过预先定义好的只能包含一个参数或没有参数的方法名生成 selector ,再根据类对象和 selector 生成NSMethodSignature ,进而由NSMethodSignature生成NSInvocation,进行方法调用,再加上参数和返回值的Lua与OC的类型转换,就完成了一次OC方法的调用。

下面再说一下 Wax 。 Wax 的源码中有这样一个文件wax_helpers.h/wax_helpers.m ,它提供了一系列的工具方法包括lua与OC的类型之间相互转化,lua中使用_的方法名转化为OC中:的selector,根据lua传递过来的方法名找到对应的 selector 等方法,有兴趣的同学可以去看看代码。

Wax 主要是维护了这样的一个结构,基本上所有与对象有关的操作都是在这个基础上完成的:

1
2
3
4
5
6
typedef struct _wax_instance_userdata {
id instance;
BOOL isClass;
Class isSuper; // isSuper not only stores whether the class is a super, but it also contains the value of the next superClass.
BOOL actAsSuper; // It only acts like a super once, when it is called for the first time.
} wax_instance_userdata;

第一个 instance 就是OC对象的一个指针, isClass 标识这是不是一个类对象, isSuper 用来标识他的父对象,类似以OC中的 isa 指针,这么做是为了在方法调用时子类如果找不到的话就会由此去父类查找, actAsSuper 用来标识这个对象是不是被当做父类来使用, Wax 中一个对象智能被当做父类一次。

Wax 中还维护了两个表,一个 UserDataTable 一个 StrongUserDataTable。这两个表中都存储的是 Wax_instance_userdata->instance 为 key ,Wax_instance_userdata 为值的键值对。 UserDataTable 是一个值为wake的弱表,他用来存储所有创建的对象,是一个弱引用,他其中就存储了通过lua创建的OC对象,因为是弱表,所以当不在使用时会调用 __gc 这个元方法,进而将该OC对象销毁。 StrongUserDataTable 是一个强引用表他保存的是所有通过 Wax 创建的对象,他不是一个弱表所以需要手动管理内存。也就是说使用 Wax 创建的对象除了会在 UserDataTable 中保存一份以外还会在 StrongUserDataTable 保存一份。

说到这里就在说一下 Wax 的内存管理, Wax 的内存管理也是基于引用计数的,而且他没有使用 AutoReleasePool 。所有引用计数的操作都在框架里为你实现好了,所以在lua里你不能调用 alloc 方法,而要直接使用 init 方法,因为他会判断你的方法是不是 init 初始化方法,如果是的话 Wax 会帮你调用 alloc 方法。对象的 release 有两种一种是 UserDataTable 中的对象会在 __gc 元方法中release ,另外一种就是在 Wax 运行的时候有一个定时器timer,不停地轮询StrongUserDataTable 中的对象的引用计数如果小于2,那么就会 release 。

Wax 创建类和对象以及方法调用都是通过元方法来实现的。 先来说创建类,就是通过定义的类名以及父类,在运行时通过字符串以及运行时的API创建一个类,通过class_addMethod() 函数给创建的这个类注册方法,而这个方法的实现就是一个IMP(函数指针),Wax中IMP是这样的一类方法,方法包括lua中用户自己写的function,在OC的层面又对这个function的参数和返回值进行了OC与lua的互转,这两部分组合起来构成一个方法。也就是当调用一个用lua写的方法的时候会首先把参数转化为lua类型然后由 lua_pcall() 调用lua中的方法,完成后再把返回值转换成OC类型的。

最后说一下 Wax 的方法调用,无论是OC自己的方法还是用户自己写的方法最终都是去调用这个IMP(函数指针),所以在这之前无论是调用OC原生的方法和用户自己定义的方法,处理的方式都是一样的。在元方法 __index 里将方法的调用作为一个closure push到lua中,在元方法 __newindex 中进行方法的override。在closure中的方法调用就和 CCLuaObjcBridge 一样了,都是先获取到 selector ,生成NSMethodSignature ,然后生成 NSInvocation ,然后调用。与CCLuaObjcBridge 不同的地方就是由于这个对象是 wax_instance_userdata中的 instance ,而不是由类名生成的类对象,所以他可以调用实例方法。

以上仅是个人一些理解,自身对Lua的C API和OC的runtime的API不是很熟悉,Wax 中使用了大量的这些API,所以有不对的地方还请指出来。

ios waxpatch lua语法的更多相关文章

  1. iOS Waxpatch项目(动态更新)

    我的iOS Waxpatch项目地址https://github.com/piaojin/iOS-WaxPatch

  2. 转:OpenResty最佳实践(推荐了解lua语法)

    看点: 1. Lua 语法的说明, 排版清晰易懂. 转: https://moonbingbing.gitbooks.io/openresty-best-practices/content/lua/m ...

  3. 让Xcode Lua 语法高亮

    本人不太喜欢用code ide 还是喜欢XCODE的风格 1.让Xcode支援Lua语法高亮(Syntax Highlighting) 1. 下载https://github.com/breinhar ...

  4. Lua语法要点

    本文在我的独立博客中的链接:https://www.bughui.com/2017/04/01/lua-grammar-points/ 这篇文章其实是我在四月一号发布的,由于我重新注册了一个博客园帐号 ...

  5. lua 语法的使用总结

    1.字符串连接 local tmp = "abc" local tmp1 = "ddd" tmp..tmp1 2. table 类型 就是关联数组 local ...

  6. Lua语法基础(2)--基本语法、函数

    上一篇编辑编辑着,发现,缩进出了问题.作为一个不是强迫症的人,实在是忍受不了同一级内容不同缩进方式的槽点,于是重开一篇吧.(万幸,这样的文章也只有我自己看.) 第四 基本语法 赋值语句,Lua可以对多 ...

  7. Lua语法要点2

    [Lua语法要点2] 1.Lua函数 function 可以添加 local 关键字.添加后为局部函数,不添加(默认)为全局函数.return 可以返回多个返回值,以, 分隔. 使用 ... 来表示变 ...

  8. ios WaxPatch热更新原理

    以下是引用他人文章内容: 为什么需要 WaxPatch 很多情况下,已经在 AppStore 上线的应用需要紧急缺陷修复,此时便需要使用某些技术手段,使应用程序能够动态下载补丁,进行缺陷修复. 什么是 ...

  9. iOS - OC 面向对象语法

    1.类 1)根类:因为类 NSObject 是层次结构的最顶层,因此称为根类. 可以将类称为子类(subclass)和父类(superclass),也可以将类称为子类和超类. 2)分类/类别(cate ...

随机推荐

  1. 【PHP面向对象(OOP)编程入门教程】16.__toString()方法

    我们前面说过在类里面声明“__”开始的方法名的方法(PHP给我们提供的),都是在某一时刻不同情况下自动调用执行的方 法,“__toString()”方法也是一样自动被调用的,是在直接输出对象引用时自动 ...

  2. 第五章第二例题关于Vector(LRJ)

    vector(动态数组)(粘) 一.概述 vector是C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库.vector是一个容器,它能够存放各种类型的对象,简 ...

  3. Gunicorn 文档翻译

    服务器模式 Gunicorn 基于 pre-fork 模式,这意味着有一个主进程管理工作的子进程.主进程对客户端的工作业务有了解.所有的请求和响应都是工作子进程处理. 主进程 主进程是一个简单的循环, ...

  4. eclipse svn

    1.上传初始项目在百度云上面创建一个空版本,然后右击项目->team->shareProject在svn的url后面加上你的版本号(否则上传失败) 2.把服务器上的项目更新到自己的项目wi ...

  5. PYTHON 自动化之路 (二)

    一.python 模块的使用 模块的使用: import os #调用 os 模块 cmd_s = os.popen("dir").read() #打开路径为结果保存为cmd_sp ...

  6. STM32F103ZET6 用定时器级联方式输出特定数目的PWM(转载)

    STM32F103ZET6里共有8个定时器,其中高级定时器有TIM1-TIM5.TIM8,共6个.这里需要使用定时器的级联功能,ST的RM0008 REV12的P388和P399页上有说明对于特定的定 ...

  7. 如何用Wireshark捕获USB数据?

    现在越来越多的电子设备采用USB接口进行通讯,通讯标准也在逐步提高.那么,我们就会好奇这些设备是如何工作的?而无论你是一个硬件黑客,业余爱好者或者只是对它有一点兴趣的,USB对我们都是具有挑战性的. ...

  8. ubuntu配置apache的虚拟主机

    ubuntu中apache的配置文件分散在几个文件中,/etc/apache2/apache2.conf将它们组织起来.这样设计有很多好处,这里就不在赘述了.进入正题: 1)配置文件在/etc/apa ...

  9. 再谈Weiphp公众平台开发——1、成语接龙插件

    易错点,注意插件的命名 1.创建插件.在weiphp管理后台创建成语接龙插件,勾选安装后立即启用,不需要配置项和管理列表.点“确定”完成插件的创建. 2.安装插件. 3.检测插件是否成功安装.返回到w ...

  10. python egg文件解压

    unzip 就可以了. 由于项目需要将某些版本的库打包,然后 sys.path.insert方式引用(避免升级包导致某些旧的系统崩掉). 在将egg文件打包时,发现不可用.但相关模块的__path__ ...