@zyl06
2019-01-21T20:47:40.000000Z
字数 9799
阅读 870
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 = false
self._groupDisposable.dispose()
end)
self:addEventListener("resumed",function()
self:hideInputMethod(nil)
if not self._isLoaded then
self:showLoading()
end
self:initData()
self:queryForCommentTotalCount()
end)
end
-- override
function PublicCameraViewController.prototype:rightBtnEvent()
self:showPopMenu(self)
end
PublicCameraViewController
base
属性指定 BaseViewController
,表示是一个 VC / Activityproperties
设置基类属性 bShowBackBtn
等和自定义属性 isPublicCameraValid
等mixins
设置模块类(category)init
rightBtnEvent
require "PublicCamera.PublicCameraViewController"
local nextVC = PublicCameraViewController.PublicCameraViewController{
deviceId = self._cellDto.deviceId,
enterPublicTime = os.date(os.time()),
}
vc:pushViewController(nextVC, true)
-- Class.lua
Class = function(name, config)
if name == nil then
name = "Anonymous" .. nameId
nameId = nameId + 1
end
return MetaClass(name, config)
end
可见 Class.Class("PublicCameraViewController", {...})
是一个方法调用
-- Class.lua
MetaClass = {}
MetaClass.className = "MetaClass"
MetaClass.prototype = MetaClassProto
MetaClassProto.constructor = MetaClass
-- MetaClass继承自Object
MetaClass.superclass = Object
setmetatableAndCopyMetaMethods(MetaClassProto, Object.prototype)
-- MetaClass' class is MetaClass
MetaClass.class = MetaClass
setmetatable(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 Object
local properties = config.properties and config.properties or {}
local mixins = config.mixins and config.mixins or {}
local statics = config.statics
local methods = config.methods
logClassStyle("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 mixins
processMixins(newCls, mixins)
--process properties
processClassProperties(newCls, properties)
--process methods
processMethods(newCls, methods)
--process static methods
processStaticMethods(newCls, statics)
return newCls
end
function createClass(base, clsName)
--construct new class
local newClsProto = {}
local newCls = {}
newClsProto.constructor = newCls
newCls.prototype = newClsProto
newClsProto.__index = newClsProto
--derive from base
newCls.superclass = base
setmetatableAndCopyMetaMethods(newClsProto, base.prototype)
--metaclass
local newMetacls = {}
local newMetaclsProto = {}
newMetacls.className = "Meta" .. clsName
newMetacls.prototype = newMetaclsProto
newMetaclsProto.constructor = newMetacls
newMetaclsProto.__index = newMetaclsProto
--newcls需要构造函数,这在lua中必须设置其metacls protype的__call字段
newMetaclsProto.__call = base.class.prototype.__call
--metaclass is derive from base's metaclass
newMetacls.superclass = base.class
setmetatableAndCopyMetaMethods(newMetaclsProto, base.class.prototype)
--newmetaclass's class is metaclass
newMetacls.class = MetaClass
setmetatable(newMetacls, MetaClass.prototype)
newCls.class = newMetacls
setmetatable(newCls, newMetaclsProto)
return newCls, newClsProto
end
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 mixins
local superCls = cls.superclass
local allmixins = table.shallowcopy(mixins)
while superCls do
if superCls.__mixins then
for k, v in pairs(superCls.__mixins) do
if allmixins[k] == nil then
allmixins[k] = v
end
end
end
superCls = superCls.superclass
end
--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, ...)
end
end)
end)
cls.__mixins = allmixins
end
-- PopMenuMixin.lua
PopMenuMixin = 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.lua
Mixin = 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) do
propertyMaps[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 的属性同样设置给 initProperties
end
-- Class.lua
-- processMethods(newCls, methods)
function processMethods(cls, methods)
local proto = cls.prototype
if methods then
for key, v in pairs(methods) do
proto[key] = v
end
end
end
-- Class.lua
-- processStaticMethods(newCls, statics)
function processStaticMethods(cls, methods)
local metacls = cls.class.prototype
if not methods then
return
end
for k, v in pairs(methods) do
metacls[k] = v
end
end
将类定义中的 static 属性中定义的方法直接设置到 cls.class.prototype
中,根据前面 createClass
方法,其实最终也是设置到 newMetaclsProto
中
function createClass(base, clsName)
...
newMetacls.prototype = newMetaclsProto
newMetaclsProto.constructor = newMetacls
newMetaclsProto.__index = newMetaclsProto
newMetacls.prototype = newMetaclsProto
setmetatable(newMetacls, MetaClass.prototype)
...
newCls.class = newMetacls
...
return newCls, newClsProto
end
前面讲述了 类定义和创建,那类对象是如何创建的,相关 init 方法等何时被调用呢?
require "PublicCamera.PublicCameraViewController"
local nextVC = PublicCameraViewController.PublicCameraViewController{
deviceId = self._cellDto.deviceId,
enterPublicTime = os.date(os.time()),
}
nextVC 对象是如何被创建的?
查看 createClass 方法:
--Class.lua
function 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, newClsProto
end
--All Class's base class
Object = {}
Object.prototype = ObjectProto
ObjectProto.constructor = Object
Object.className = "Object"
--MetaObjectProto
MetaObjectProto = {}
MetaObjectProto.__index = MetaObjectProto
...
--MetaObject
MetaObject = {}
MetaObject.className = "MetaObject"
MetaObject.prototype = MetaObjectProto
MetaObjectProto.constructor = MetaObject
Object.class = MetaObject
setmetatable(Object, MetaObjectProto)
--MetaObject继承自Object
setmetatableAndCopyMetaMethods(MetaObjectProto, ObjectProto)
MetaObject.superclass = Object
--MetametaClass
MetaClassProto = {}
MetaClassProto.__index = MetaClassProto
MetaObjectProto.__call = function(cls, ...)
-- 1. 创建实例
local self = setmetatable({}, cls.prototype)
-- 2. 设置对象的类属性
self.class = cls
-- 3. 将类的 minixs 属性给 对象
initMixins(self, cls)
self.isIniting = yesF
self.isBeforeInit = yesF
-- 4. 如果有自定义初始化方法,则执行自定义方法,若无则执行默认初始化方法 processInitializedProperties
if cls.processInitProperties then
cls.processInitProperties(cls, self)
else
processInitializedProperties(cls, self)
end
self.isBeforeInit = notF
-- 5. 执行 init 方法
if cls.init then
self:init(...)
end
self.isIniting = notF
return self
end
local processInitializedProperties = function(cls, obj)
local initProperties = nil
if not cls.initProperties then return end
for i, propMap in pairs(cls.initProperties) do
local val = propMap.initV
if val ~= undefined then
if propMap.needCopy then
local newVal = {}
for key, v in pairs(val) do
newVal[key] = v
end
doSetter(obj, propMap.setterName, newVal)
--obj[propMap.setterName](obj, newVal)
else
doSetter(obj, propMap.setterName, val)
-- obj[propMap.setterName](obj, val)
end
end
end
end