Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

iOS中Lua脚本的应用

2,854 views

Published on

How To Use Lua In iOS

Published in: Education, Technology
  • Be the first to comment

iOS中Lua脚本的应用

  1. 1. iOS中Lua脚本的应用 Proteas 2012-07-23 proteas.wang@gmail.com
  2. 2. 概要 • 为什么要在应用中引入脚本? • 为什么是 Lua ? • 使用 Lua 开发应用的几种模式 • Hello Lua • Meta-*: Lua 与 Objective-C 集成的原理 • wax 框架及其本身的一些问题 • Demos • 其它 • 目前没有解决的问题
  3. 3. 为什么要在应用中引入脚本? • 目前在进行开发应用时遇到的一些问题 – UI 变化 – 业务逻辑变化 – 数据源不灵活 • 如何处理 UI 变化? • 如何处理业务逻辑变化? • 如何解决数据源不灵活的问题? • ObjC 语言的问题(编译执行) * Warning:使用 PList 作为配置文件时要谨 慎
  4. 4. 为什么是 Lua ? • 设计目标:嵌入到应用程序中(嵌入式) • 体积小:100~200K • 最快的脚本语言(非 JIT) • 简洁的 API • 动态语言 • Domain Specific Language * 编程语言的哲学: – 编程语言是否都差不多? – Assembly,C,C++,Java/C#,Python, Ruby,Common Lisp – 代码与数据的统一
  5. 5. 使用 Lua 开发应用的几种模式 • Lua作为配置文件 ,为宿主语言应用 提供参数 宿主语言 Lua • 宿主语言作为底层 库,Lua 作为逻辑描 述 Lua 宿主语言 * Lua VS. Plist or XML Corona SDK
  6. 6. Hello Lua:什么是 Lua • Lua是一种脚本编程语言,于1994年,由巴西里 约热内卢天主教大学的研究人员设计开发, “Lua”这个名字是葡萄牙语单词 “月亮”。 • 与一般脚本语言如 PHP、Perl、JavaScript 等不 同,Lua被称为是一种嵌入式脚本语言,Lua最著 名的应用是在暴雪公司的网络游戏 魔兽世界 中。 – 《World of Warcraft Programming》 • Lua最引人注目的特点: – 以极小 的体积和简单 的语法提供相对全面的功能。 – 以简洁 的API实现与宿主语言最方便 的接口。 • 在服务器端也有着广泛的应用
  7. 7. Hello Lua:为什么称为“嵌入式” • Lua语言可以独立进行编程,但这不是其主要的 使用方式。Lua虽然有动态、灵活的语法提供强 大的功能,但并不像 Java、Python 等一样有一 个完善的库(但仍存在一定数量的第三方库), 这不是缺陷,而是和其定位有关。 • Lua最典型的用法,是作为一个库,嵌入 到其他 大型语言(称之为宿主语言 )的应用程序之中, 为应用程序提供参数配置或逻辑描述等功能,带 来前所未有的灵活性。 • Lua常见的宿主语言有:C/C++,Java,.NET, 甚至脚本语言如PHP,Ruby等。
  8. 8. Hello Lua:工作流程 • 1.宿主语言建立Lua解释器对象。 • 2.将宿主语言实现的Lua扩展(若有),如函数等 ,注册到Lua解释器中,供其使用。 • 3.读入Lua源程序或预先编译后的Lua程序(可以 从文件、字符串、网络等任意来源)。 • 4.执行读入的Lua程序。
  9. 9. Hello Lua:lua_State
  10. 10. Hello Lua:变量 • Lua 是动态语言,变量没有类型,存储的值才有类型 • 八个基本类型 * 点对 • var = 4 • var = “hello” • var = {x = 10, y = 20} • a, b = 1, 2
  11. 11. Hello Lua:控制结构 • 条件判断:if • 迭代: – while – repeat – for
  12. 12. Hello Lua:控制结构-If • if Statement if a <= 0 then a = a + 1 end if a < 0 then a = a + 1 elseif a > 0 then a = a – 1 else a = 0 end Nested if-else statement Simple if statement
  13. 13. Hello Lua:控制结构-While • While Loop Lua first tests the while condition, if it is false then the loop ends, otherwise it executes the body a = {1,2,3,4,5} i = 1 while a[i] do print(a[i]) i = i + 1 end Output: 1,2,3,4,5
  14. 14. Hello Lua:控制结构-Repeat • Repeat Repeat-until statement repeats its body until the condition is true. This ensures that the body of the loop is executed at least once. a = 0 repeat a = a + 1 print(a) until a > 10 Output: 1,2,3,4,5,6,7,8,9,10,11 This block always executes at least once
  15. 15. Hello Lua:控制结构-Numeric Loop • Numeric For Loop for i=1,10,1 do print(i) end Output: 1,2,3,4,5,6,7,8,9,10 Initial condition Evaluate to Increment by
  16. 16. Hello Lua:控制结构-Generic Loop • Generic For Loop – Allows you to traverse all values returned by an iterator function colors = {“red”, “green”, “blue”} for i,v in ipairs(colors) do print(i,v) end Output: 1 red, 2 green, 3 blue Iterator Functionindex value
  17. 17. Hello Lua:函数 • 函数是第一类型 • 定义函数 • 调用 function add(a, b) c = a + b return c end x = add(1, 2) print(x) 输出:3
  18. 18. Hello Lua:Closure • Closures – A function which returns a function – Has full access to local variables – This allows Lua to implement functional programming function newCounter() local i = 0 return function() i = i + 1 return i end end Anonymous function c1 = newCounter() print(c1()) --> 1 print(c1()) --> 2 c2 = newCounter() print(c2()) --> 1 print(c1()) --> 3 print(c2()) --> 2 * UpValues:lobject.h(231~)
  19. 19. Hello Lua:数据结构-Table • 创建:t = {1, 2,3, 4, 5} • 取值:t[1], t[2] • 从 1 开始索引 • t = {apple="green", orange="orange", banana="yellow"} • t[“apple”], t[“orange”], t[“banana”] • t = { 2,4,6, language="Lua", version="5.1" }
  20. 20. Hello Lua:Meta Table • t = {1, 2, 3} • mt = {} • setmetatable(t, mt) • 数据结构:lobject.h(338~348) * 如果不是开源代码呢?
  21. 21. Hello Lua:Meta Methods > x = { value = 3 } -- our object > > mt = { __add = function (a, b) >> return { value = a.value + b.value } >> end } -- metatable containing event callbacks > > a = x + x -- without a metatable this is just a regular table stdin:1: attempt to perform arithmetic on global `x' (a table value) stack traceback: stdin:1: in main chunk [C]: ? > > setmetatable(x, mt) -- attach our metamethods to our object > > a = x + x -- try again > print(a.value) 6
  22. 22. Hello Lua:Meta Methods 原型 作用 __index Control 'prototype' inheritance. if the value is a function, the function is called, passing in the table and the key; the return value of that function is returned as the result. __newindex Control property assignment. When calling myTable[key] = value, if the metatable has a __newindex key pointing to a function, call that function, passing it the table, key, and value. __call Treat a table like a function. When a table is followed by parenthesis such as myTable( 'foo' ) and the metatable has a __call key pointing to a function, that function is invoked (passing any specified arguments) and the return value is returned. __add Addition __sub Subtraction … … * 横向比较
  23. 23. Hello Lua:Meta Methods -- create a namespace Window = {} -- create the prototype with default values Window.prototype = {x = 0, y = 0, width = 100, height = 100, } -- create a metatable Window.mt = {} -- declare the constructor function function Window.new (o) setmetatable(o, Window.mt) return o end
  24. 24. Hello Lua:Meta Methods Now, we define the __index metamethod: Window.mt.__index = function (table, key) return Window.prototype[key] end After that code, we create a new window and query it for an absent field: w = Window.new{x = 10, y = 20} print(w.width) --> 100 When Lua detects that w does not have the requested field, but has a metatable with an __index field, Lua calls this __index metamethod, with arguments w (the table) and "width" (the absent key). The metamethod then indexes the prototype with the given key and returns the result.
  25. 25. Hello Lua:Meta Methods classWrapper = {name = “NSObject”, instance = nil} mt = {} mt.__call = function(table) table.instance = 0xFFFF; -- 初始化 end Setmetatable(classWrapper, mt) 主要用来做初始化 typedef struct _wax_instance_userdata { id instance; BOOL isClass; Class isSuper; BOOL actAsSuper; } wax_instance_userdata; 此处的初始化是指使用运行时方法创建类。
  26. 26. Hello Lua:Meta Methods classWrapper = {name = “NSObject”, instance = nil} mt = {} mt.__call = function(table) table.instance = 0xFFFF; -- 初始化 end Setmetatable(classWrapper, mt) 主要用来做初始化 typedef struct _wax_instance_userdata { id instance; BOOL isClass; Class isSuper; BOOL actAsSuper; } wax_instance_userdata; 此处的初始化是指使用运行时方法创建类。
  27. 27. Lua 与 ObjC 集成的原理 • Objective-C Runtime API: – <objc/runtime.h>, <objc/message.h> – objc_allocateClassPair – class_addIvar – class_addMethod – … • Lua 的 meta 特性: – UserData:C Struct – __index(lua_State *L) – __call(lua_State *L); – C Function Closure
  28. 28. Lua 与 ObjC 集成的原理 • 需要解决的两个问题: – 在 Lua 中生成 ObjC 的 Class • 利用 UserData,ObjC Runtime API – 将 Lua 的调用转换为 ObjC 的调用 • 利用 Lua 的 C Function Closure, NSInvocation * meta programming – meta data – 编译时的特性 – Common Lisp 的 s-expression – C++ 的 meta template programming – lex/yacc
  29. 29. wax 框架及其本身的一些问题 • https://github.com/probablycorey/wax/ • 设计目标:使用 Lua 开发应用 – ObjC 为 Lua 提供库 – 只提供单向的辅助函数:ObjC→Lua – 只提供一个 lua_State • 对 wax 做了部分修改 • 其他的一些库: – Lua-Objective-C-Bridge – LuaCocoa * 开源库的选择方法
  30. 30. Demos:初始化与释放 初始化的是 lua_State 单例: wax_start("SampleScript.lua", NULL); // TODO: wax_end(); 多例: lua_State *lv = fm_start("SampleScript.lua", NULL); // TODO: fm_end(lv);
  31. 31. Demos:从Lua中读取整型 Lua: count = 2 ObjC: // number lua_getglobal(L, "count"); int count = lua_tonumber(L, -1); NSLog(@"Count From Lua: %d", count); lua_pop(L, 1);
  32. 32. Demos:从Lua中读取字符串 Lua: msg = “hello everyone” ObjC: // string lua_getglobal(L, "msg"); const char *msg = lua_tostring(L, -1); NSLog(@"Msg From Lua: %s", msg); lua_pop(L, 1);
  33. 33. Demos:从Lua中读取ObjC变量 Lua: alertView = UIAlertView :initWithTitle_message_delegate_cancelButtonTitle_otherButtonTitles( nil, "Hello Lua!", nil, "确定", nil); ObjC: // objc var lua_getglobal(L, "alertView"); UIAlertView *alertView = fm_instance_getObject(L, -1); [alertView show]; lua_pop(L, 1);
  34. 34. Demos:调用Lua函数-1 Lua: -- Lua Functions function SayHello() print("hello lua!") end endObjC: //wax_printStack(_luaState); lua_getglobal(_luaState, "SayHello"); //wax_printStack(_luaState); wax_pcall(_luaState, 0, 0); //wax_printStack(_luaState); lua_pop(_luaState, 1); //wax_printStack(_luaState);
  35. 35. Demos:调用Lua函数-2 Lua: function SayHello2(msg) print(msg) end ObjC: lua_getglobal(_luaState, "SayHello2"); lua_pushstring(_luaState, "msg from objc"); wax_pcall(_luaState, 1, 0); lua_pop(_luaState, 1);
  36. 36. Demos:调用Lua函数-3 Lua: function SayHello3(msgDict) msg = msgDict["msg"] print(msg) end endObjC: lua_getglobal(_luaState, "SayHello3"); NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys: @"hello lua from objc", @"msg", nil]; wax_fromInstance(_luaState, dict); wax_pcall(_luaState, 1, 0); lua_pop(_luaState, 1);
  37. 37. Demos:调用Lua函数-4 Lua: -- with object function SayHello4(obj) obj:sayHello(toobjc("hello from lua")) end ObjC: - (void)sayHello:(NSString *)msg { UIAlertView *alertView = [[[UIAlertView alloc] initWithTitle:@"Call from lua" message:msg delegate:nil cancelButtonTitle:@"Cancel" otherButtonTitles:nil] autorelease]; [alertView show]; } - (void)callLuaWithObject:(id)sender { lua_getglobal(_luaState, "SayHello4"); wax_fromInstance(_luaState, self); wax_pcall(_luaState, 1, 0); lua_pop(_luaState, 1); }
  38. 38. Demos:调用Lua函数-5 Lua: -- return string function SayHello5() return "raw string from lua" end ObjC: lua_getglobal(_luaState, "SayHello5"); wax_pcall(_luaState, 0, 1); const char *msg = lua_tostring(_luaState, -1); [self sayHello:[NSString stringWithUTF8String:msg]]; lua_pop(_luaState, 1);
  39. 39. Demos:调用Lua函数-6 Lua: -- return objc string function SayHello6() return toobjc("objc string from lua") end ObjC: lua_getglobal(_luaState, "SayHello6"); wax_pcall(_luaState, 0, 1); NSString *msg = (NSString *)fm_instance_getObject(_luaState, -1); [self sayHello:msg]; lua_pop(_luaState, 1);
  40. 40. Demos:调用C函数 C: static int SampleCFunction(lua_State *L) { const char *param = lua_tostring(L, -1); … return 0; } lua_pushcfunction(_luaState, SampleCFunction); lua_setglobal(_luaState, "showMsg"); Lua: function SayHello7() return showMsg("hi") end ObjC: lua_getglobal(_luaState, "SayHello7"); wax_pcall(_luaState, 0, 0); lua_pop(_luaState, 1);
  41. 41. 其他 • 胶水语言 • 多大的接口粒度是合适的? • 在业务领域中应用Lua的切入点
  42. 42. 讨论? 谢谢!

×