問(wèn)題介紹:
項(xiàng)目中有一種組件式的UI相满,即一些UI的小部件层亿,可以隨時(shí)地卸載或顯示,而不依賴于當(dāng)前所在的場(chǎng)景立美,如左上角角色信息棕所、右上角小地圖、菜單悯辙、聊天框等。為了統(tǒng)一地對(duì)這些組件UI進(jìn)行管理迎吵,需要做到:
- 開發(fā)更多組件UI時(shí)躲撰,需要實(shí)現(xiàn)展示和隱藏的接口
- 統(tǒng)一地管理添加、刪除和隱藏組件UI
- 索引不影響UI對(duì)象的正常釋放
實(shí)現(xiàn):
為了在任何場(chǎng)景中都可以有選擇的動(dòng)態(tài)添加击费、刪除或隱藏這些UI部件拢蛋,我約定了一個(gè)組件UI接口類UIComponent,然后用一個(gè)全局列表索引所有組件蔫巩,這樣對(duì)外只需要留很少的接口就可以管理這些組件了谆棱。
但是快压,由于組件的UI有可能因?yàn)楦鞣N形式被程序的邏輯移除,導(dǎo)致組件UI的索引表失效垃瞧,于是便引入了python的弱引用蔫劣。
python的內(nèi)存是通過(guò)引用計(jì)數(shù)和垃圾回收來(lái)管理的,當(dāng)一個(gè)Python對(duì)象被引用時(shí)其引用計(jì)數(shù)增加1个从,當(dāng)其不再被一個(gè)變量引用時(shí)則計(jì)數(shù)減1脉幢。當(dāng)引用計(jì)數(shù)等于0時(shí)對(duì)象被刪除。我們可以很輕易地用sys.getrefcount(o)這個(gè)函數(shù)來(lái)打印出python對(duì)象的引用計(jì)數(shù)嗦锐。
同時(shí)嫌松,python也提供了一個(gè)weakref模塊,創(chuàng)建了一個(gè)弱引用后奕污,可以引用python的對(duì)象萎羔,而不增加其引用計(jì)數(shù)。弱引用提供一個(gè)函數(shù)來(lái)查詢所引用的對(duì)象是否有效碳默。
下面是python里面使用弱引用的例子:
>>> import sys
>>> import weakref
>>> class Class1:
def test(self):
print "test..."
>>> o = Class1()
>>> sys.getrefcount(o)
2
>>> r = weakref.ref(o) # 創(chuàng)建一個(gè)弱引用
11
>>> sys.getrefcount(o) # 引用計(jì)數(shù)并沒(méi)有改變
2
>>> o = None
>>> r # 當(dāng)對(duì)象引用計(jì)數(shù)為零時(shí)贾陷,弱引用失效。
<weakref at 00D3B3F0; dead>
這樣腻窒,上面的組件UI全局索引改成對(duì)UI對(duì)象弱引用的索引昵宇,而不用影響UI對(duì)象的正常釋放回收。相當(dāng)于一個(gè)透明對(duì)這些組件UI進(jìn)行管理儿子。
class UIComponent(object):
"""組件式的UI瓦哎,統(tǒng)一隱藏和顯示行為"""
def __init__(self, host):
self._ret_host = weakref.ref(host)
self._show_ui_callback = None
self._hide_ui_callback = None
# 創(chuàng)建宿主的弱引用,檢查宿主失效柔逼,并清理
G_COMPONENT_UI[self._ret_host] = weakref.ref(self)
def destory(self):
del G_COMPONENT_UI[self._ret_host]
def show_component_ui_callback(self, callback):
self._show_ui_callback = callback
def hide_component_ui_callback(self, callback):
self._hide_ui_callback = callback
G_COMPONENT_UI = {}
def hide_all_compent_ui():
del_list = []
for ref_host, ui_component in G_COMPONENT_UI.iteritems():
host = ref_host()
if not host:
del_list.append(ref_host)
else:
ui_component = ui_component()
if not ui_component:
del_list.append(ref_host)
elif ui_component._hide_ui_callback:
ui_component._hide_ui_callback()
else:
if hasattr(host,"hide"):
host.hide()
for i,ref_host in enumerate(del_list):
del G_COMPONENT_UI[ref_host]