问题介绍:
项目中有一种组件式的UI,即一些UI的小部件,可以随时地卸载或显示,而不依赖于当前所在的场景,如左上角角色信息、右上角小地图、菜单、聊天框等。为了统一地对这些组件UI进行管理,需要做到:
1. 开发更多组件UI时,需要实现展示和隐藏的接口
2. 统一地管理添加、删除和隐藏组件UI
3. 索引不影响UI对象的正常释放
实现:
为了在任何场景中都可以有选择的动态添加、删除或隐藏这些UI部件,我约定了一个组件UI接口类UIComponent,然后用一个全局列表索引所有组件,这样对外只需要留很少的接口就可以管理这些组件了。
但是,由于组件的UI有可能因为各种形式被程序的逻辑移除,导致组件UI的索引表失效,于是便引入了python的弱引用。
python的内存是通过引用计数和垃圾回收来管理的,当一个Python对象被引用时其引用计数增加1,当其不再被一个变量引用时则计数减1。当引用计数等于0时对象被删除。我们可以很轻易地用sys.getrefcount(o)这个函数来打印出python对象的引用计数。
同时,python也提供了一个weakref模块,创建了一个弱引用后,可以引用python的对象,而不增加其引用计数。弱引用提供一个函数来查询所引用的对象是否有效。
下面是python里面使用弱引用的例子:
08 |
>>> sys.getrefcount(o) |
10 |
>>> r = weakref.ref(o) |
11 |
>>> sys.getrefcount(o) |
15 |
<weakref at 00D3B3F0 ; dead> |
这样,上面的组件UI全局索引改成对UI对象弱引用的索引,而不用影响UI对象的正常释放回收。相当于一个透明对这些组件UI进行管理。
01 |
class UIComponent( object ): |
03 |
def __init__( self ,
host): |
04 |
self ._ret_host = weakref.ref(host) |
06 |
self ._show_ui_callback = None |
07 |
self ._hide_ui_callback = None |
10 |
G_COMPONENT_UI[ self ._ret_host] = weakref.ref( self ) |
13 |
del G_COMPONENT_UI[ self ._ret_host] |
15 |
def show_component_ui_callback( self ,
callback): |
16 |
self ._show_ui_callback = callback |
18 |
def hide_component_ui_callback( self ,
callback): |
19 |
self ._hide_ui_callback = callback |
22 |
def hide_all_compent_ui(): |
24 |
for ref_host,
ui_component in G_COMPONENT_UI.iteritems(): |
27 |
del_list.append(ref_host) |
29 |
ui_component = ui_component() |
31 |
del_list.append(ref_host) |
32 |
elif ui_component._hide_ui_callback: |
33 |
ui_component._hide_ui_callback() |
35 |
if hasattr (host, "hide" ): |
38 |
for i,ref_host in enumerate (del_list): |
39 |
del G_COMPONENT_UI[ref_host] |