ColorTouch class 機(jī)制

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,表示是一個(gè) VC / Activity
  3. properties 設(shè)置基類屬性 bShowBackBtn 等和自定義屬性 isPublicCameraValid
  4. mixins 設(shè)置模塊類(category)
  5. 定義類初始化接口 init
  6. 定義類的自定義方法 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)
  1. 引入 module尘喝,并創(chuàng)建實(shí)例 nextVC
  2. 打開 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)
  1. 創(chuàng)建 MetaClass table炕倘,并且設(shè)置 MetaClassProto 為 MetaClass.prototype
  2. 設(shè)置 MetaClassProto 為 MetaClass 的 metatable
  3. 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
  1. 創(chuàng)建 newClsnewClsProto 對象拯坟,其中 newClsmetatablenewMetaclsProto但金,newMetaclsProto__call 屬性為 base.class.prototype.__call。由此在創(chuàng)建 newCls 的實(shí)例時(shí)郁季,會(huì)調(diào)用基類 prototype.__call 方法傲绣,進(jìn)而實(shí)現(xiàn)基類的各個(gè)屬性的初始化

  2. 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
  1. 將 cls 自身和全部基類的 mixins 收集到 allmixins
  2. 將 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)建 PublicCameraViewControllerPopMenuMixin 之間的關(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
  1. 將初始化變量中的方法,設(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
  1. 將類定義中的 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
  1. 調(diào)用 PublicCameraViewController.PublicCameraViewController(...) 時(shí)啊易,則會(huì)查找 newCls 實(shí)例 metatable 中的 __call 方法,即 newMetaclsProto.__call 方法饮睬,即 base.class.prototype.__call
  2. 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
  1. 將 cls 中的屬性值 set 給對象昼丑,并觸發(fā) setXXX 方法呻逆,同時(shí)觸發(fā) onXXXChanged 方法,部分屬性觸發(fā) native 方法執(zhí)行
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末菩帝,一起剝皮案震驚了整個(gè)濱河市咖城,隨后出現(xiàn)的幾起案子茬腿,更是在濱河造成了極大的恐慌,老刑警劉巖宜雀,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件切平,死亡現(xiàn)場離奇詭異,居然都是意外死亡辐董,警方通過查閱死者的電腦和手機(jī)悴品,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來简烘,“玉大人苔严,你說我怎么就攤上這事】溲校” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵依鸥,是天一觀的道長亥至。 經(jīng)常有香客問我,道長贱迟,這世上最難降的妖魔是什么姐扮? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮衣吠,結(jié)果婚禮上茶敏,老公的妹妹穿的比我還像新娘。我一直安慰自己缚俏,他們只是感情好惊搏,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著忧换,像睡著了一般恬惯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上亚茬,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天酪耳,我揣著相機(jī)與錄音,去河邊找鬼刹缝。 笑死碗暗,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的梢夯。 我是一名探鬼主播言疗,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼颂砸!你這毒婦竟也來了洲守?” 一聲冷哼從身側(cè)響起疑务,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎梗醇,沒想到半個(gè)月后知允,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡叙谨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年温鸽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片手负。...
    茶點(diǎn)故事閱讀 39,696評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡涤垫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出竟终,到底是詐尸還是另有隱情蝠猬,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布统捶,位于F島的核電站榆芦,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏喘鸟。R本人自食惡果不足惜匆绣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望什黑。 院中可真熱鬧崎淳,春花似錦、人聲如沸愕把。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽恨豁。三九已至咐鹤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間圣絮,已是汗流浹背祈惶。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留扮匠,地道東北人捧请。 一個(gè)月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像棒搜,于是被迫代替她去往敵國和親疹蛉。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉力麸,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,709評論 0 9
  • Objective-C語言是一門動(dòng)態(tài)語言可款,他將很多靜態(tài)語言在編譯和鏈接時(shí)期做的事情放到了運(yùn)行時(shí)來處理育韩。這種動(dòng)態(tài)語言...
    tigger丨閱讀 1,398評論 0 8
  • 本文轉(zhuǎn)載自:http://southpeak.github.io/2014/10/25/objective-c-r...
    idiot_lin閱讀 933評論 0 4
  • Objective-C語言是一門動(dòng)態(tài)語言,它將很多靜態(tài)語言在編譯和鏈接時(shí)期做的事放到了運(yùn)行時(shí)來處理闺鲸。這種動(dòng)態(tài)語言的...
    有一種再見叫青春閱讀 583評論 0 3
  • 包(lib)筋讨、模塊(module) 在Python中,存在包和模塊兩個(gè)常見概念摸恍。 模塊:編寫Python代碼的py...
    清清子衿木子水心閱讀 3,802評論 0 27