美文网首页
ColorTouch class 机制

ColorTouch class 机制

作者: zyl06 | 来源:发表于2019-01-21 20:48 被阅读81次

    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
    
    1. 定义类 PublicCameraViewController
    2. 基类由 base 属性指定 BaseViewController,表示是一个 VC / Activity
    3. properties 设置基类属性 bShowBackBtn 等和自定义属性 isPublicCameraValid
    4. mixins 设置模块类(category)
    5. 定义类初始化接口 init
    6. 定义类的自定义方法 rightBtnEvent

    1 类实例的创建和使用

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

    2 类机制的简单介绍

    2.1 类创建

    -- 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)
    
    1. 创建 MetaClass table,并且设置 MetaClassProto 为 MetaClass.prototype
    2. 设置 MetaClassProto 为 MetaClass 的 metatable
    3. MetaClassProto.__call 被定义,所以当调用 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
    
    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

    --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
    
    1. 将 cls 自身和全部基类的 mixins 收集到 allmixins
    2. 将 allmixnins 中的方法设置给 cls.prototype
      • 即当 cls 调用一个 mixin 方法时,自身找不到,则查找 metatable __index table(即 prototype)中的属性,则查找到前面的 prototype 中设置的 mixin method 属性中指定的方法,即可调用
    -- 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 属性
    由此构建 PublicCameraViewControllerPopMenuMixin 之间的关系:PublicCameraViewController 可以调用 PopMenuMixin 暴露的 methods 方法,PopMenuMixin 可以通过 getOwner() 获取 PublicCameraViewController 对象。

    2.3 初始化属性(对象创建传入的属性,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. 将构建对象时,自定义的属性设置给 props 设置给 cls 实例(self)的 initProperties,同时构建 get 和 set 方法。
        -- 2. 将 class 定义时的属性设置给 initProperties,遍历全部的 super class 的属性同样设置给 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
    
    1. 将初始化变量中的方法,设置到 cls.prototype 中

    2.5 初始化静态方法

    -- 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
    
    1. 将类定义中的 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
      

    3 类实例创建

    前面讲述了 类定义和创建,那类对象是如何创建的,相关 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
    
    1. 调用 PublicCameraViewController.PublicCameraViewController(...) 时,则会查找 newCls 实例 metatable 中的 __call 方法,即 newMetaclsProto.__call 方法,即 base.class.prototype.__call
    2. base 的最终基类是 Object,Object.MetaObject 是 MetaObject,MetaObject 的 prototype 为 MetaObjectProto, MetaObjectProto.__call 方法已经被定义
    --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
    
    1. 将 cls 中的属性值 set 给对象,并触发 setXXX 方法,同时触发 onXXXChanged 方法,部分属性触发 native 方法执行

    相关文章

      网友评论

          本文标题:ColorTouch class 机制

          本文链接:https://www.haomeiwen.com/subject/yxmhjqtx.html