2012年时候还在做iOS,OC里有个NotifationCenter蛮好用的,之后做Coscos2d也有这个, 然Unity并没有这个,且Unity SendMessage的消息机制效率低下,而且inactive的物件收不到消息,还只能带一个参数,忒不好用。 C#的Action和委托倒是好,但是公司项目里用多播注册事件的地方,很多人忘记取消注册,导致各种bug,我心酸。心想还是自己写个NotificationCenter吧。
代码如下:
/*
Author: Danny
CreateDate: 2016-08-27 09:22:01
Desc: Custom NotificationCenter
*/
using UnityEngine;
using System.Collections.Generic;
using System;
using System.Collections;
public class NotificationCenter
{
public static NotificationCenter DefaultCenter
{
get
{
if (defaultCenter == null)
{
defaultCenter = new NotificationCenter();
}
return defaultCenter;
}
}
private static NotificationCenter defaultCenter;
private NotificationCenter()
{
notifications = new Hashtable();
}
private Hashtable notifications;
public delegate void NotificationHandler0();
public delegate void NotificatonHandlerN(params object[] args);
public void AddObserver(object observer, string notification, NotificationHandler0 handler)
{
AddObserverFunc(observer, notification, handler);
}
public void AddObserver(object observer, string notification, NotificatonHandlerN handler)
{
AddObserverFunc(observer, notification, handler);
}
private void AddObserverFunc(object observer, string notification, object handler)
{
if (string.IsNullOrEmpty(notification))
{
Debug.Log("Null notification specified for notification in AddObserver.");
return;
}
if (observer == null)
{
Debug.Log("Null observer specified for notification in AddObserver.");
return;
}
if (notifications[notification] == null)
{
notifications[notification] = new Dictionary<object, object>();
}
var handlers = notifications[notification] as Dictionary<object, object>;
if (!handlers.ContainsKey(observer))
{
handlers.Add(observer, handler);
}
}
public void RemoveObserver(object observer, string notification)
{
if (notifications[notification] == null)
{
Debug.LogWarning("No need to remove notification not exist");
return;
}
var handlers = notifications[notification] as Dictionary<object, object>;
if (handlers != null)
{
if (handlers.ContainsKey(observer))
{
handlers.Remove(observer);
}
}
if (handlers.Count == 0)
{
notifications.Remove(notification);
}
}
private List<object> observersToRemove = new List<object>();
public void PostNotification(string notification, params object[] args)
{
var handlers = notifications[notification] as Dictionary<object, object>;
observersToRemove.Clear();
if (handlers != null)
{
foreach (var handler in handlers)
{
if (handler.Key != null)
{
if (handler.Value != null)
{
if (handler.Value is NotificationHandler0)
{
(handler.Value as NotificationHandler0)();
if (args.Length != 0)
{
Debug.LogWarning(string.Format("handler '{0}' receive useless paramter.
notfication: {1}", handler.Value, notification));
}
}
else
{
(handler.Value as NotificatonHandlerN)(args);
}
}
else
{
Debug.LogError(string.Format("Opps! Receive notification '{0}',
but handler has been destroyed ", notification));
}
}
else
{
Debug.LogError(string.Format("Opps! Receive notification '{0}',
but observer has been destroyed ", notification));
observersToRemove.Add(handler.Key);
}
}
}
if (observersToRemove.Count > 0)
{
foreach (var o in observersToRemove)
{
handlers.Remove(o);
}
}
}
}
接口:
public void AddObserver(object observer, string notification, NotificationHandler0 handler)
public void AddObserver(object observer, string notification, NotificatonHandlerN handler)
public void RemoveObserver(object observer, string notification)
public void PostNotification(string notification, params object[] args)
需要注意的是,observer的handler可以无参数或者有参数, handler在observer里声明的时候,如果有参数,形参类型必须是object[],用的时候做类型转换, 调用PostNotification()的时候需注意参数数目和顺序。
具体实例如下:
using UnityEngine;
using System.Collections;
public class TestView: MonoBehaviour
{
void Start()
{
NotificationCenter.DefaultCenter.AddObserver(this, "HideTestViewNotify", HideUI);
NotificationCenter.DefaultCenter.AddObserver(this, "ModelChangeNotify", RefreshUI);
}
void OnDestroy()
{
NotificationCenter.DefaultCenter.RemoveObserver(this, "HideTestViewNotify");
NotificationCenter.DefaultCenter.RemoveObserver(this, "ModelChangeNotify");
}
void HideUI()
{
// to hdie ui
}
void RefreshUI(object[] data)
{
var model = data[0] as ModelDataStructure;
// do more thing..
}
}
public class ModelManager
{
void OnModelDataChanged(ModelDataStructure data)
{
NotificationCenter.DefaultCenter.PostNotification("ModelChangeNotify", data);
}
void DoSomethingToHideUI()
{
NotificationCenter.DefaultCenter.PostNotification("HideTestViewNotify");
}
}
public class ModelDataStructure
{
}
–EOF–