0 類的定義
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
,表示是一個(gè) VC / Activity - 由
properties
設(shè)置基類屬性bShowBackBtn
等和自定義屬性isPublicCameraValid
等 - 由
mixins
設(shè)置模塊類(category) - 定義類初始化接口
init
- 定義類的自定義方法
rightBtnEvent
1 類實(shí)例的創(chuàng)建和使用
require "PublicCamera.PublicCameraViewController"
local nextVC = PublicCameraViewController.PublicCameraViewController{
deviceId = self._cellDto.deviceId,
enterPublicTime = os.date(os.time()),
}
vc:pushViewController(nextVC, true)
- 引入 module尘喝,并創(chuàng)建實(shí)例 nextVC
- 打開 VC/Activity
2 類機(jī)制的簡單介紹
2.1 類創(chuàng)建
-- 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", {...})
是一個(gè)方法調(diào)用
-- Class.lua
MetaClass = {}
MetaClass.className = "MetaClass"
MetaClass.prototype = MetaClassProto
MetaClassProto.constructor = MetaClass
-- MetaClass繼承自O(shè)bject
MetaClass.superclass = Object
setmetatableAndCopyMetaMethods(MetaClassProto, Object.prototype)
-- MetaClass' class is MetaClass
MetaClass.class = MetaClass
setmetatable(MetaClass, MetaClassProto)
- 創(chuàng)建 MetaClass table炕倘,并且設(shè)置 MetaClassProto 為 MetaClass.prototype
- 設(shè)置 MetaClassProto 為 MetaClass 的 metatable
- MetaClassProto.__call 被定義,所以當(dāng)調(diào)用
MetaClass(name, config)
時(shí)瘤运,會(huì)調(diào)用到 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需要構(gòu)造函數(shù)窍霞,這在lua中必須設(shè)置其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
創(chuàng)建
newCls
,newClsProto
對象拯坟,其中newCls
的metatable
為newMetaclsProto
但金,newMetaclsProto
的__call
屬性為base.class.prototype.__call
。由此在創(chuàng)建 newCls 的實(shí)例時(shí)郁季,會(huì)調(diào)用基類prototype.__call
方法傲绣,進(jìn)而實(shí)現(xiàn)基類的各個(gè)屬性的初始化-
setmetatableAndCopyMetaMethods(newMetaclsProto, base.class.prototype) 設(shè)置基類 prototype 為 newMetaclsProto 的 metatable,為此 newCls 繼承了基類 base.class.prototype 中的全部屬性
- 當(dāng)取 newCls 的屬性 a巩踏,在 newCls 中查找秃诵,找到則返回
- 找不到,則查找 newMetaclsProto.__index table(也就是 newMetaclsProto 自己)塞琼,找到則返回
- 找不到菠净,則查找 base.class.prototype.__index 中的屬性,根據(jù)遞歸特性,__index 就是 base.class.prototype 自身毅往,即在 base.class.prototype 查找屬性
- 一層層查找 super class prototype 中的屬性牵咙,直到找到
2.2 初始化 mixin
--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中所有導(dǎo)出的方法平坦到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
- 將 cls 自身和全部基類的 mixins 收集到 allmixins
- 將 allmixnins 中的方法設(shè)置給 cls.prototype
- 即當(dāng) cls 調(diào)用一個(gè) mixin 方法時(shí)攀唯,自身找不到洁桌,則查找 metatable __index table(即 prototype)中的屬性,則查找到前面的 prototype 中設(shè)置的 mixin method 屬性中指定的方法侯嘀,即可調(diào)用
-- 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
如前面設(shè)置的 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
}
})
當(dāng) PopMenuMixin init 方法調(diào)用的時(shí)候戒幔,將
PublicCameraViewController
設(shè)置為PopMenuMixin
的 owner 屬性
由此構(gòu)建PublicCameraViewController
和PopMenuMixin
之間的關(guān)系:PublicCameraViewController
可以調(diào)用PopMenuMixin
暴露的 methods 方法吠谢,PopMenuMixin
可以通過 getOwner() 獲取PublicCameraViewController
對象。
2.3 初始化屬性(對象創(chuàng)建傳入的屬性诗茎,class 中定義的屬性)
-- 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. 將構(gòu)建對象時(shí)工坊,自定義的屬性設(shè)置給 props 設(shè)置給 cls 實(shí)例(self)的 initProperties,同時(shí)構(gòu)建 get 和 set 方法敢订。
-- 2. 將 class 定義時(shí)的屬性設(shè)置給 initProperties王污,遍歷全部的 super class 的屬性同樣設(shè)置給 initProperties
end
2.4 初始化普通方法
-- 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
- 將初始化變量中的方法,設(shè)置到 cls.prototype 中
2.5 初始化靜態(tài)方法
-- 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 屬性中定義的方法直接設(shè)置到
cls.class.prototype
中楚午,根據(jù)前面createClass
方法玉掸,其實(shí)最終也是設(shè)置到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
3 類實(shí)例創(chuàng)建
前面講述了 類定義和創(chuàng)建,那類對象是如何創(chuàng)建的醒叁,相關(guān) init 方法等何時(shí)被調(diào)用呢司浪?
require "PublicCamera.PublicCameraViewController"
local nextVC = PublicCameraViewController.PublicCameraViewController{
deviceId = self._cellDto.deviceId,
enterPublicTime = os.date(os.time()),
}
nextVC 對象是如何被創(chuàng)建的?
查看 createClass 方法:
--Class.lua
function createClass(base,clsName)
--construct new class
...
local newMetaclsProto = {}
...
newMetaclsProto.__index = newMetaclsProto
--newcls需要構(gòu)造函數(shù)把沼,這在lua中必須設(shè)置其metacls protype的__call字段
newMetaclsProto.__call = base.class.prototype.__call
...
setmetatableAndCopyMetaMethods(newMetaclsProto, base.class.prototype)
...
setmetatable(newCls, newMetaclsProto)
return newCls, newClsProto
end
- 調(diào)用 PublicCameraViewController.PublicCameraViewController(...) 時(shí)啊易,則會(huì)查找 newCls 實(shí)例 metatable 中的 __call 方法,即 newMetaclsProto.__call 方法饮睬,即 base.class.prototype.__call
- base 的最終基類是 Object租谈,Object.MetaObject 是 MetaObject,MetaObject 的 prototype 為 MetaObjectProto捆愁, MetaObjectProto.__call 方法已經(jīng)被定義
--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繼承自O(shè)bject
setmetatableAndCopyMetaMethods(MetaObjectProto, ObjectProto)
MetaObject.superclass = Object
--MetametaClass
MetaClassProto = {}
MetaClassProto.__index = MetaClassProto
MetaObjectProto.__call = function(cls, ...)
-- 1. 創(chuàng)建實(shí)例
local self = setmetatable({}, cls.prototype)
-- 2. 設(shè)置對象的類屬性
self.class = cls
-- 3. 將類的 minixs 屬性給 對象
initMixins(self, cls)
self.isIniting = yesF
self.isBeforeInit = yesF
-- 4. 如果有自定義初始化方法割去,則執(zhí)行自定義方法,若無則執(zhí)行默認(rèn)初始化方法 processInitializedProperties
if cls.processInitProperties then
cls.processInitProperties(cls, self)
else
processInitializedProperties(cls, self)
end
self.isBeforeInit = notF
-- 5. 執(zhí)行 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
- 將 cls 中的屬性值 set 給對象昼丑,并觸發(fā) setXXX 方法呻逆,同時(shí)觸發(fā) onXXXChanged 方法,部分屬性觸發(fā) native 方法執(zhí)行