@zyl06
2019-01-21T12:47:40.000000Z
字数 9799
阅读 1086
Lua 动态化
module("PublicCameraViewController", package.seeall)local BaseViewController = require "Base.BaseViewController"local screenWidth = getApplication():getViewportWidth()require "PublicCamera.PopMenuMixin"....PublicCameraViewController = Class.Class("PublicCameraViewController",{base = BaseViewController,properties={deviceId = Class.undefined,model = Class.undefined,rightImagePath = "app://icon_more.png",bShowNaviBar = true,bShowBackBtn = true,......--判断摄像头是否失效isPublicCameraValid = true,},},mixins = {popMenu = PopMenuMixin,.....}})function PublicCameraViewController.prototype:init(inlineprops, ...)BaseViewController.prototype.init(self, inlineprops, ...)...self:addEventListener("popped",function()self._isDataInited = falseself._groupDisposable.dispose()end)self:addEventListener("resumed",function()self:hideInputMethod(nil)if not self._isLoaded thenself:showLoading()endself:initData()self:queryForCommentTotalCount()end)end-- overridefunction PublicCameraViewController.prototype:rightBtnEvent()self:showPopMenu(self)end
PublicCameraViewControllerbase 属性指定 BaseViewController,表示是一个 VC / Activityproperties 设置基类属性 bShowBackBtn 等和自定义属性 isPublicCameraValid 等mixins 设置模块类(category)initrightBtnEvent
require "PublicCamera.PublicCameraViewController"local nextVC = PublicCameraViewController.PublicCameraViewController{deviceId = self._cellDto.deviceId,enterPublicTime = os.date(os.time()),}vc:pushViewController(nextVC, true)
-- Class.luaClass = function(name, config)if name == nil thenname = "Anonymous" .. nameIdnameId = nameId + 1endreturn MetaClass(name, config)end
可见 Class.Class("PublicCameraViewController", {...}) 是一个方法调用
-- Class.luaMetaClass = {}MetaClass.className = "MetaClass"MetaClass.prototype = MetaClassProtoMetaClassProto.constructor = MetaClass-- MetaClass继承自ObjectMetaClass.superclass = ObjectsetmetatableAndCopyMetaMethods(MetaClassProto, Object.prototype)-- MetaClass' class is MetaClassMetaClass.class = MetaClasssetmetatable(MetaClass, MetaClassProto)
MetaClass(name, config) 时,会调用到 MetaClass metatable (即 MetaClassProto) 的 __call 方法
MetaClassProto.__call = function(self, name, config)config = config and config or {}local base = config.base and config.base or Objectlocal properties = config.properties and config.properties or {}local mixins = config.mixins and config.mixins or {}local statics = config.staticslocal methods = config.methodslogClassStyle("create class, base:%s", base:address())local newCls, newClsProto = createClass(base, name)logClassStyle("newed class:%s, classproto:%s", newCls:address(), newCls.prototype:address())newCls.className = name--process mixinsprocessMixins(newCls, mixins)--process propertiesprocessClassProperties(newCls, properties)--process methodsprocessMethods(newCls, methods)--process static methodsprocessStaticMethods(newCls, statics)return newClsend
function createClass(base, clsName)--construct new classlocal newClsProto = {}local newCls = {}newClsProto.constructor = newClsnewCls.prototype = newClsProtonewClsProto.__index = newClsProto--derive from basenewCls.superclass = basesetmetatableAndCopyMetaMethods(newClsProto, base.prototype)--metaclasslocal newMetacls = {}local newMetaclsProto = {}newMetacls.className = "Meta" .. clsNamenewMetacls.prototype = newMetaclsProtonewMetaclsProto.constructor = newMetaclsnewMetaclsProto.__index = newMetaclsProto--newcls需要构造函数,这在lua中必须设置其metacls protype的__call字段newMetaclsProto.__call = base.class.prototype.__call--metaclass is derive from base's metaclassnewMetacls.superclass = base.classsetmetatableAndCopyMetaMethods(newMetaclsProto, base.class.prototype)--newmetaclass's class is metaclassnewMetacls.class = MetaClasssetmetatable(newMetacls, MetaClass.prototype)newCls.class = newMetaclssetmetatable(newCls, newMetaclsProto)return newCls, newClsProtoend
newCls,newClsProto 对象,其中 newCls 的 metatable 为 newMetaclsProto,newMetaclsProto 的 __call 属性为 base.class.prototype.__call。由此在创建 newCls 的实例时,会调用基类 prototype.__call 方法,进而实现基类的各个属性的初始化setmetatableAndCopyMetaMethods(newMetaclsProto, base.class.prototype) 设置基类 prototype 为 newMetaclsProto 的 metatable,为此 newCls 继承了基类 base.class.prototype 中的全部属性
--processMixins(newCls, mixins)function processMixins(cls, mixins)--1. collection all mixinslocal superCls = cls.superclasslocal allmixins = table.shallowcopy(mixins)while superCls doif superCls.__mixins thenfor k, v in pairs(superCls.__mixins) doif allmixins[k] == nil thenallmixins[k] = vendendendsuperCls = superCls.superclassend--2. 将mixins中所有导出的方法平坦到cls.prototype中,superclass的mixins不需要平坦table.each(allmixins,function(mixin, name)local methods = mixin:methods()table.each(methods,function(method)cls.prototype[method] = function(obj, ...)local mixin = obj.mixins[name]return mixin[method](mixin, ...)endend)end)cls.__mixins = allmixinsend
-- PopMenuMixin.luaPopMenuMixin = Class.Class("PopMenuMixin",{base = Mixin,properties = {vc = Class.undefined,popMenu = Class.undefined,preVC = Class.undefined,},statics = {methods = function ()return {"showPopMenu",}end}})function PopMenuMixin.prototype:init(owner)Mixin.prototype.init(self, owner)end--显示菜单function PopMenuMixin.prototype:showPopMenu(vc)...end
如前面设置的 mixin
PopMenuMixin,则提供给PublicCameraViewController的方法为showPopMenu。
-- Mixin.luaMixin = Class.Class("Mixin",{properties={owner=Class.undefined,},methods={init=function(self, owner)self:setOwner(owner)end},statics={methods=function(self)return {}end}})
当 PopMenuMixin init 方法调用的时候,将
PublicCameraViewController设置为PopMenuMixin的 owner 属性
由此构建PublicCameraViewController和PopMenuMixin之间的关系:PublicCameraViewController可以调用PopMenuMixin暴露的 methods 方法,PopMenuMixin可以通过 getOwner() 获取PublicCameraViewController对象。
-- Class.lua-- processClassProperties(newCls, properties)local processClassProperties = function(cls, props)-- logClassStyle("process properties:%s", table.tostring(props))local propertyMaps = {}for k, v in pairs(props) dopropertyMaps[k] = {propName = k,realPropName = NameMap[k][1],--"_" .. k,getterName = NameMap[k][2],--string.getterName(k),setterName = NameMap[k][3],--string.setterName(k),changedEvtName = NameMap[k][4],--string.propChangeEvtName(k),applyName = NameMap[k][5],--string.applyName(k),initV = v,needCopy = getmetatable(v) == nil and type(v) == 'table',}end-- 1. 将构建对象时,自定义的属性设置给 props 设置给 cls 实例(self)的 initProperties,同时构建 get 和 set 方法。-- 2. 将 class 定义时的属性设置给 initProperties,遍历全部的 super class 的属性同样设置给 initPropertiesend
-- Class.lua-- processMethods(newCls, methods)function processMethods(cls, methods)local proto = cls.prototypeif methods thenfor key, v in pairs(methods) doproto[key] = vendendend
-- Class.lua-- processStaticMethods(newCls, statics)function processStaticMethods(cls, methods)local metacls = cls.class.prototypeif not methods thenreturnendfor k, v in pairs(methods) dometacls[k] = vendend
将类定义中的 static 属性中定义的方法直接设置到 cls.class.prototype 中,根据前面 createClass 方法,其实最终也是设置到 newMetaclsProto 中
function createClass(base, clsName)...newMetacls.prototype = newMetaclsProtonewMetaclsProto.constructor = newMetaclsnewMetaclsProto.__index = newMetaclsProtonewMetacls.prototype = newMetaclsProtosetmetatable(newMetacls, MetaClass.prototype)...newCls.class = newMetacls...return newCls, newClsProtoend
前面讲述了 类定义和创建,那类对象是如何创建的,相关 init 方法等何时被调用呢?
require "PublicCamera.PublicCameraViewController"local nextVC = PublicCameraViewController.PublicCameraViewController{deviceId = self._cellDto.deviceId,enterPublicTime = os.date(os.time()),}
nextVC 对象是如何被创建的?
查看 createClass 方法:
--Class.luafunction createClass(base,clsName)--construct new class...local newMetaclsProto = {}...newMetaclsProto.__index = newMetaclsProto--newcls需要构造函数,这在lua中必须设置其metacls protype的__call字段newMetaclsProto.__call = base.class.prototype.__call...setmetatableAndCopyMetaMethods(newMetaclsProto, base.class.prototype)...setmetatable(newCls, newMetaclsProto)return newCls, newClsProtoend
--All Class's base classObject = {}Object.prototype = ObjectProtoObjectProto.constructor = ObjectObject.className = "Object"--MetaObjectProtoMetaObjectProto = {}MetaObjectProto.__index = MetaObjectProto...--MetaObjectMetaObject = {}MetaObject.className = "MetaObject"MetaObject.prototype = MetaObjectProtoMetaObjectProto.constructor = MetaObjectObject.class = MetaObjectsetmetatable(Object, MetaObjectProto)--MetaObject继承自ObjectsetmetatableAndCopyMetaMethods(MetaObjectProto, ObjectProto)MetaObject.superclass = Object--MetametaClassMetaClassProto = {}MetaClassProto.__index = MetaClassProto
MetaObjectProto.__call = function(cls, ...)-- 1. 创建实例local self = setmetatable({}, cls.prototype)-- 2. 设置对象的类属性self.class = cls-- 3. 将类的 minixs 属性给 对象initMixins(self, cls)self.isIniting = yesFself.isBeforeInit = yesF-- 4. 如果有自定义初始化方法,则执行自定义方法,若无则执行默认初始化方法 processInitializedPropertiesif cls.processInitProperties thencls.processInitProperties(cls, self)elseprocessInitializedProperties(cls, self)endself.isBeforeInit = notF-- 5. 执行 init 方法if cls.init thenself:init(...)endself.isIniting = notFreturn selfend
local processInitializedProperties = function(cls, obj)local initProperties = nilif not cls.initProperties then return endfor i, propMap in pairs(cls.initProperties) dolocal val = propMap.initVif val ~= undefined thenif propMap.needCopy thenlocal newVal = {}for key, v in pairs(val) donewVal[key] = venddoSetter(obj, propMap.setterName, newVal)--obj[propMap.setterName](obj, newVal)elsedoSetter(obj, propMap.setterName, val)-- obj[propMap.setterName](obj, val)endendendend