最近处理了一个几个版本之前遗留的问题,代码是一个离职的同事写的,测试发现了这个问题,但是不能稳定重现,所以一直没有修改。最近有玩家反馈过来,重现几率比较大,于是用玩家的号重现这个问题。
现象:战斗时会偶发性的缺少一些数据。具体表现是进战斗时有六个武将,但是显示出来会缺少一些武将。
经过多次调试,发现进战斗数据没有问题,只是显示出现了问题,显示的地方是取View代码里面的数据,并未修改。
代码逻辑:
1、先从对象池查看是否有空闲View,有就取出来使用,没有就新创建,将使用的对象放到队列里面保存下来,使用完成之后,根据这个队列将对象放回对象池。
2、根据自己的需求修改对象。
3、将使用后的对象放回对象池。
逻辑整体上没有什么问题,但是新加了个战斗模式之后,同事在第一步新增加了一个队列存放对象,在第三步,放回对象池时,将两个队列里面,相同的对象放回了对象池。这样下一次从对象池取数据的时候,有可能在需要两个对象时,取出来的是两个相同的对象。在修改数据时,第二个对象永远会覆盖第一个的数据引起bug。
代码逻辑大概是如下:
public class TestData
{
public int TestNum;
public void Dispose()
{
TestNum = 0;
}
}
private List<TestData> m_testDataList1 = new List<TestData>();
private List<TestData> m_testDataList2 = new List<TestData>();
private Queue<TestData> m_testDataCacheList = new Queue<TestData>();
public int TestA = 0;
public int TestB = 0;
private TestData ShowTestDataA;
private TestData ShowTestDataB;
private void OtherSystem()
{
EditorGUILayout.BeginVertical();
if (GUILayout.Button("获取数据"))
{
ShowTestDataA = CreateData();
//模拟取数据
for (int i = 0; i < 2; i++)
{
ShowTestDataB = CreateData();
}
//模拟将数据加了两次
m_testDataList1.Add(ShowTestDataA);
m_testDataList1.Add(ShowTestDataB);
m_testDataList2.Add(ShowTestDataA);
m_testDataList2.Add(ShowTestDataB);
if (ShowTestDataA == ShowTestDataB)
{
Log.Error("如果取出来两个对象地址相同+++++++++++++++");
}
}
TestA = EditorGUILayout.IntField("TestA:", TestA);
TestB = EditorGUILayout.IntField("TestB:", TestB);
if (GUILayout.Button("修改数据"))
{
ChangeData(ShowTestDataA, TestA);
ChangeData(ShowTestDataB,TestB);
}
if (GUILayout.Button("回收数据"))
{
//模拟将同一个对象添加到对象池。
for (int i = 0; i < m_testDataList2.Count; i++)
{
DisposeData(m_testDataList2[i]);
}
for (int i = 0; i < m_testDataList1.Count; i++)
{
DisposeData(m_testDataList1[i]);
}
m_testDataList1.Clear();
m_testDataList2.Clear();
}
if (GUILayout.Button("清除缓存"))
{
m_testDataList1.Clear();
m_testDataList2.Clear();
m_testDataCacheList.Clear();
}
if (ShowTestDataA != null)
{
GUILayout.Label("ShowTestDataA:" + ShowTestDataA.TestNum.ToString());
}
if (ShowTestDataB != null)
{
GUILayout.Label("ShowTestDataB:" + ShowTestDataB.TestNum.ToString());
}
EditorGUILayout.EndVertical();
}
private void ChangeData(TestData data,int num)
{
if (data == null)
{
return;
}
data.TestNum = num;
}
private void DisposeData(TestData data)
{
if (data ==null)
{
return;
}
data.Dispose();
if (m_testDataCacheList.Contains(data))
{
Log.Error("存进来的对象相同");
}
m_testDataCacheList.Enqueue(data);
}
private TestData CreateData()
{
if (m_testDataCacheList.Count > 0)
{
TestData data = m_testDataCacheList.Dequeue();
return data;
}
else
{
TestData data = new TestData();
return data;
}
}
因为对象池可能将一个对象存入两次,导致取出来时可能会将同一个对象的地址分配给两个对象,修改数据时出现问题。
修改:在将对象放入对象池时,判断一下对象是否相同。