[关闭]
@zyl06 2019-01-21T20:47:40.000000Z 字数 9799 阅读 870

ColorTouch class 机制

Lua 动态化


0 类的定义

  1. module("PublicCameraViewController", package.seeall)
  2. local BaseViewController = require "Base.BaseViewController"
  3. local screenWidth = getApplication():getViewportWidth()
  4. require "PublicCamera.PopMenuMixin"
  5. ....
  6. PublicCameraViewController = Class.Class("PublicCameraViewController",
  7. {
  8. base = BaseViewController,
  9. properties={
  10. deviceId = Class.undefined,
  11. model = Class.undefined,
  12. rightImagePath = "app://icon_more.png",
  13. bShowNaviBar = true,
  14. bShowBackBtn = true,
  15. ......
  16. --判断摄像头是否失效
  17. isPublicCameraValid = true,
  18. },
  19. },
  20. mixins = {
  21. popMenu = PopMenuMixin,
  22. .....
  23. }
  24. })
  25. function PublicCameraViewController.prototype:init(inlineprops, ...)
  26. BaseViewController.prototype.init(self, inlineprops, ...)
  27. ...
  28. self:addEventListener("popped",
  29. function()
  30. self._isDataInited = false
  31. self._groupDisposable.dispose()
  32. end)
  33. self:addEventListener("resumed",function()
  34. self:hideInputMethod(nil)
  35. if not self._isLoaded then
  36. self:showLoading()
  37. end
  38. self:initData()
  39. self:queryForCommentTotalCount()
  40. end)
  41. end
  42. -- override
  43. function PublicCameraViewController.prototype:rightBtnEvent()
  44. self:showPopMenu(self)
  45. end
  1. 定义类 PublicCameraViewController
  2. 基类由 base 属性指定 BaseViewController,表示是一个 VC / Activity
  3. properties 设置基类属性 bShowBackBtn 等和自定义属性 isPublicCameraValid
  4. mixins 设置模块类(category)
  5. 定义类初始化接口 init
  6. 定义类的自定义方法 rightBtnEvent

1 类实例的创建和使用

  1. require "PublicCamera.PublicCameraViewController"
  2. local nextVC = PublicCameraViewController.PublicCameraViewController{
  3. deviceId = self._cellDto.deviceId,
  4. enterPublicTime = os.date(os.time()),
  5. }
  6. vc:pushViewController(nextVC, true)
  1. 引入 module,并创建实例 nextVC
  2. 打开 VC/Activity

2 类机制的简单介绍

2.1 类创建

  1. -- Class.lua
  2. Class = function(name, config)
  3. if name == nil then
  4. name = "Anonymous" .. nameId
  5. nameId = nameId + 1
  6. end
  7. return MetaClass(name, config)
  8. end

可见 Class.Class("PublicCameraViewController", {...}) 是一个方法调用

  1. -- Class.lua
  2. MetaClass = {}
  3. MetaClass.className = "MetaClass"
  4. MetaClass.prototype = MetaClassProto
  5. MetaClassProto.constructor = MetaClass
  6. -- MetaClass继承自Object
  7. MetaClass.superclass = Object
  8. setmetatableAndCopyMetaMethods(MetaClassProto, Object.prototype)
  9. -- MetaClass' class is MetaClass
  10. MetaClass.class = MetaClass
  11. setmetatable(MetaClass, MetaClassProto)
  1. 创建 MetaClass table,并且设置 MetaClassProto 为 MetaClass.prototype
  2. 设置 MetaClassProto 为 MetaClass 的 metatable
  3. MetaClassProto.__call 被定义,所以当调用 MetaClass(name, config) 时,会调用到 MetaClass metatable (即 MetaClassProto) 的 __call 方法
  1. MetaClassProto.__call = function(self, name, config)
  2. config = config and config or {}
  3. local base = config.base and config.base or Object
  4. local properties = config.properties and config.properties or {}
  5. local mixins = config.mixins and config.mixins or {}
  6. local statics = config.statics
  7. local methods = config.methods
  8. logClassStyle("create class, base:%s", base:address())
  9. local newCls, newClsProto = createClass(base, name)
  10. logClassStyle("newed class:%s, classproto:%s", newCls:address(), newCls.prototype:address())
  11. newCls.className = name
  12. --process mixins
  13. processMixins(newCls, mixins)
  14. --process properties
  15. processClassProperties(newCls, properties)
  16. --process methods
  17. processMethods(newCls, methods)
  18. --process static methods
  19. processStaticMethods(newCls, statics)
  20. return newCls
  21. end
  1. function createClass(base, clsName)
  2. --construct new class
  3. local newClsProto = {}
  4. local newCls = {}
  5. newClsProto.constructor = newCls
  6. newCls.prototype = newClsProto
  7. newClsProto.__index = newClsProto
  8. --derive from base
  9. newCls.superclass = base
  10. setmetatableAndCopyMetaMethods(newClsProto, base.prototype)
  11. --metaclass
  12. local newMetacls = {}
  13. local newMetaclsProto = {}
  14. newMetacls.className = "Meta" .. clsName
  15. newMetacls.prototype = newMetaclsProto
  16. newMetaclsProto.constructor = newMetacls
  17. newMetaclsProto.__index = newMetaclsProto
  18. --newcls需要构造函数,这在lua中必须设置其metacls protype__call字段
  19. newMetaclsProto.__call = base.class.prototype.__call
  20. --metaclass is derive from base's metaclass
  21. newMetacls.superclass = base.class
  22. setmetatableAndCopyMetaMethods(newMetaclsProto, base.class.prototype)
  23. --newmetaclass's class is metaclass
  24. newMetacls.class = MetaClass
  25. setmetatable(newMetacls, MetaClass.prototype)
  26. newCls.class = newMetacls
  27. setmetatable(newCls, newMetaclsProto)
  28. return newCls, newClsProto
  29. end
  1. 创建 newClsnewClsProto 对象,其中 newClsmetatablenewMetaclsProtonewMetaclsProto__call 属性为 base.class.prototype.__call。由此在创建 newCls 的实例时,会调用基类 prototype.__call 方法,进而实现基类的各个属性的初始化
  2. setmetatableAndCopyMetaMethods(newMetaclsProto, base.class.prototype) 设置基类 prototype 为 newMetaclsProto 的 metatable,为此 newCls 继承了基类 base.class.prototype 中的全部属性

    • 当取 newCls 的属性 a,在 newCls 中查找,找到则返回
    • 找不到,则查找 newMetaclsProto.__index table(也就是 newMetaclsProto 自己),找到则返回
    • 找不到,则查找 base.class.prototype.__index 中的属性,根据递归特性,__index 就是 base.class.prototype 自身,即在 base.class.prototype 查找属性
    • 一层层查找 super class prototype 中的属性,直到找到

2.2 初始化 mixin

  1. --processMixins(newCls, mixins)
  2. function processMixins(cls, mixins)
  3. --1. collection all mixins
  4. local superCls = cls.superclass
  5. local allmixins = table.shallowcopy(mixins)
  6. while superCls do
  7. if superCls.__mixins then
  8. for k, v in pairs(superCls.__mixins) do
  9. if allmixins[k] == nil then
  10. allmixins[k] = v
  11. end
  12. end
  13. end
  14. superCls = superCls.superclass
  15. end
  16. --2. mixins中所有导出的方法平坦到cls.prototype中,superclassmixins不需要平坦
  17. table.each(allmixins,
  18. function(mixin, name)
  19. local methods = mixin:methods()
  20. table.each(methods,
  21. function(method)
  22. cls.prototype[method] = function(obj, ...)
  23. local mixin = obj.mixins[name]
  24. return mixin[method](mixin, ...)
  25. end
  26. end)
  27. end)
  28. cls.__mixins = allmixins
  29. end
  1. 将 cls 自身和全部基类的 mixins 收集到 allmixins
  2. 将 allmixnins 中的方法设置给 cls.prototype
    • 即当 cls 调用一个 mixin 方法时,自身找不到,则查找 metatable __index table(即 prototype)中的属性,则查找到前面的 prototype 中设置的 mixin method 属性中指定的方法,即可调用
  1. -- PopMenuMixin.lua
  2. PopMenuMixin = Class.Class("PopMenuMixin",
  3. {
  4. base = Mixin,
  5. properties = {
  6. vc = Class.undefined,
  7. popMenu = Class.undefined,
  8. preVC = Class.undefined,
  9. },
  10. statics = {
  11. methods = function ()
  12. return {"showPopMenu",}
  13. end
  14. }
  15. }
  16. )
  17. function PopMenuMixin.prototype:init(owner)
  18. Mixin.prototype.init(self, owner)
  19. end
  20. --显示菜单
  21. function PopMenuMixin.prototype:showPopMenu(vc)
  22. ...
  23. end

如前面设置的 mixin PopMenuMixin,则提供给 PublicCameraViewController 的方法为 showPopMenu

  1. -- Mixin.lua
  2. Mixin = Class.Class("Mixin",
  3. {
  4. properties={
  5. owner=Class.undefined,
  6. },
  7. methods={
  8. init=function(self, owner)
  9. self:setOwner(owner)
  10. end
  11. },
  12. statics={
  13. methods=function(self)
  14. return {}
  15. end
  16. }
  17. })

当 PopMenuMixin init 方法调用的时候,将 PublicCameraViewController 设置为 PopMenuMixin 的 owner 属性
由此构建 PublicCameraViewControllerPopMenuMixin 之间的关系:PublicCameraViewController 可以调用 PopMenuMixin 暴露的 methods 方法,PopMenuMixin 可以通过 getOwner() 获取 PublicCameraViewController 对象。

2.3 初始化属性(对象创建传入的属性,class 中定义的属性)

  1. -- Class.lua
  2. -- processClassProperties(newCls, properties)
  3. local processClassProperties = function(cls, props)
  4. -- logClassStyle("process properties:%s", table.tostring(props))
  5. local propertyMaps = {}
  6. for k, v in pairs(props) do
  7. propertyMaps[k] = {
  8. propName = k,
  9. realPropName = NameMap[k][1],--"_" .. k,
  10. getterName = NameMap[k][2],--string.getterName(k),
  11. setterName = NameMap[k][3],--string.setterName(k),
  12. changedEvtName = NameMap[k][4],--string.propChangeEvtName(k),
  13. applyName = NameMap[k][5],--string.applyName(k),
  14. initV = v,
  15. needCopy = getmetatable(v) == nil and type(v) == 'table',
  16. }
  17. end
  18. -- 1. 将构建对象时,自定义的属性设置给 props 设置给 cls 实例(self)的 initProperties,同时构建 get set 方法。
  19. -- 2. class 定义时的属性设置给 initProperties,遍历全部的 super class 的属性同样设置给 initProperties
  20. end

2.4 初始化普通方法

  1. -- Class.lua
  2. -- processMethods(newCls, methods)
  3. function processMethods(cls, methods)
  4. local proto = cls.prototype
  5. if methods then
  6. for key, v in pairs(methods) do
  7. proto[key] = v
  8. end
  9. end
  10. end
  1. 将初始化变量中的方法,设置到 cls.prototype 中

2.5 初始化静态方法

  1. -- Class.lua
  2. -- processStaticMethods(newCls, statics)
  3. function processStaticMethods(cls, methods)
  4. local metacls = cls.class.prototype
  5. if not methods then
  6. return
  7. end
  8. for k, v in pairs(methods) do
  9. metacls[k] = v
  10. end
  11. end
  1. 将类定义中的 static 属性中定义的方法直接设置到 cls.class.prototype 中,根据前面 createClass 方法,其实最终也是设置到 newMetaclsProto

    1. function createClass(base, clsName)
    2. ...
    3. newMetacls.prototype = newMetaclsProto
    4. newMetaclsProto.constructor = newMetacls
    5. newMetaclsProto.__index = newMetaclsProto
    6. newMetacls.prototype = newMetaclsProto
    7. setmetatable(newMetacls, MetaClass.prototype)
    8. ...
    9. newCls.class = newMetacls
    10. ...
    11. return newCls, newClsProto
    12. end

3 类实例创建

前面讲述了 类定义和创建,那类对象是如何创建的,相关 init 方法等何时被调用呢?

  1. require "PublicCamera.PublicCameraViewController"
  2. local nextVC = PublicCameraViewController.PublicCameraViewController{
  3. deviceId = self._cellDto.deviceId,
  4. enterPublicTime = os.date(os.time()),
  5. }

nextVC 对象是如何被创建的?

查看 createClass 方法:

  1. --Class.lua
  2. function createClass(base,clsName)
  3. --construct new class
  4. ...
  5. local newMetaclsProto = {}
  6. ...
  7. newMetaclsProto.__index = newMetaclsProto
  8. --newcls需要构造函数,这在lua中必须设置其metacls protype__call字段
  9. newMetaclsProto.__call = base.class.prototype.__call
  10. ...
  11. setmetatableAndCopyMetaMethods(newMetaclsProto, base.class.prototype)
  12. ...
  13. setmetatable(newCls, newMetaclsProto)
  14. return newCls, newClsProto
  15. end
  1. 调用 PublicCameraViewController.PublicCameraViewController(...) 时,则会查找 newCls 实例 metatable 中的 __call 方法,即 newMetaclsProto.__call 方法,即 base.class.prototype.__call
  2. base 的最终基类是 Object,Object.MetaObject 是 MetaObject,MetaObject 的 prototype 为 MetaObjectProto, MetaObjectProto.__call 方法已经被定义
  1. --All Class's base class
  2. Object = {}
  3. Object.prototype = ObjectProto
  4. ObjectProto.constructor = Object
  5. Object.className = "Object"
  6. --MetaObjectProto
  7. MetaObjectProto = {}
  8. MetaObjectProto.__index = MetaObjectProto
  9. ...
  10. --MetaObject
  11. MetaObject = {}
  12. MetaObject.className = "MetaObject"
  13. MetaObject.prototype = MetaObjectProto
  14. MetaObjectProto.constructor = MetaObject
  15. Object.class = MetaObject
  16. setmetatable(Object, MetaObjectProto)
  17. --MetaObject继承自Object
  18. setmetatableAndCopyMetaMethods(MetaObjectProto, ObjectProto)
  19. MetaObject.superclass = Object
  20. --MetametaClass
  21. MetaClassProto = {}
  22. MetaClassProto.__index = MetaClassProto
  1. MetaObjectProto.__call = function(cls, ...)
  2. -- 1. 创建实例
  3. local self = setmetatable({}, cls.prototype)
  4. -- 2. 设置对象的类属性
  5. self.class = cls
  6. -- 3. 将类的 minixs 属性给 对象
  7. initMixins(self, cls)
  8. self.isIniting = yesF
  9. self.isBeforeInit = yesF
  10. -- 4. 如果有自定义初始化方法,则执行自定义方法,若无则执行默认初始化方法 processInitializedProperties
  11. if cls.processInitProperties then
  12. cls.processInitProperties(cls, self)
  13. else
  14. processInitializedProperties(cls, self)
  15. end
  16. self.isBeforeInit = notF
  17. -- 5. 执行 init 方法
  18. if cls.init then
  19. self:init(...)
  20. end
  21. self.isIniting = notF
  22. return self
  23. end
  1. local processInitializedProperties = function(cls, obj)
  2. local initProperties = nil
  3. if not cls.initProperties then return end
  4. for i, propMap in pairs(cls.initProperties) do
  5. local val = propMap.initV
  6. if val ~= undefined then
  7. if propMap.needCopy then
  8. local newVal = {}
  9. for key, v in pairs(val) do
  10. newVal[key] = v
  11. end
  12. doSetter(obj, propMap.setterName, newVal)
  13. --obj[propMap.setterName](obj, newVal)
  14. else
  15. doSetter(obj, propMap.setterName, val)
  16. -- obj[propMap.setterName](obj, val)
  17. end
  18. end
  19. end
  20. end
  1. 将 cls 中的属性值 set 给对象,并触发 setXXX 方法,同时触发 onXXXChanged 方法,部分属性触发 native 方法执行
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注