最近、数バージョン前に残っていた問題に対処しました。そのコードは会社を辞めた同僚が書いたもので、テストでこの問題が見つかりましたが、安定して再現できなかったため、修正されていません。最近、一部のプレイヤーが再発の可能性が比較的高いと報告したため、プレイヤーのアカウントを使用してこの問題を再現しました。
現象:戦闘中、まれに一部のデータが欠落することがあります。具体的な演出としては、参戦時には将軍が6人いるのですが、一部の将軍が欠けていると表示されてしまいます。
何度もデバッグを行った結果、戦闘データの入力には問題ないが、表示に問題があることが判明し、表示される箇所はViewコード内のデータを取り込んで修正するものではありませんでした。
コードロジック:
1. まずオブジェクト プールからアイドル状態の View があるかどうかを確認し、それを取り出して使用します。ない場合は、新しい View を作成し、使用したオブジェクトをキューに入れて保存し、使用後、オブジェクトをキューに戻します。キューに応じたオブジェクト プール。
2. 必要に応じてオブジェクトを変更します。
3. 使用したオブジェクトをオブジェクト プールに戻します。
全体のロジックには問題はありませんが、新しい戦闘モードを追加した後、同僚が最初のステップでオブジェクトを格納するための新しいキューを追加し、3 番目のステップでオブジェクトをオブジェクト プールに戻すときに同じものを追加しました。 2 つのキュー内のオブジェクト オブジェクト プールに戻ります。このようにして、次回オブジェクト プールからデータをフェッチするときに、2 つのオブジェクトが必要なときに、2 つの同一のオブジェクトがフェッチされる可能性があります。データを変更すると、2 番目のオブジェクトが最初のデータを常に上書きしてバグが発生します。
コードロジックはおおよそ次のとおりです。
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;
}
}
オブジェクト プールにはオブジェクトが 2 重に格納される可能性があるため、オブジェクトを取り出すときに同じオブジェクトのアドレスが 2 つのオブジェクトに割り当てられる可能性があり、データを変更するときに問題が発生します。
修正: オブジェクトをオブジェクトプールに入れる際に、それらのオブジェクトが同一かどうかを判断するようにしました。