2016-04-23 8 views
1

私はUnity3Dでゲームを書いています。私はWebリクエストの代理人ではなく、イベントや他の構造を完全に使うべきかどうか疑問に思っています。デリゲートコールバック内で削除された状態のオブジェクトに対する保護

ゲームのライフサイクルの特定の時点で、REST APIを呼び出してレスポンスを待つ必要があります。あなたの友人のリストを取得し、各友人のエントリと共に、友人の数を表示するUI画面を考えてみましょう。現在、ワークフローは私のServerクラスのさまざまなメソッドのパラメータとしてActionデリゲートを使用して、次のようになります。

Server.GetFriends方法は、私たちのREST APIへのHTTPリクエストを行いレスポンスを取得し、デリゲートを呼び出します
class FriendsUI : MonoBehaviour 
{ 
    [SerializeField] 
    private Text friendCount; // A Unity Text component 

    private void OnStart() 
    { 
     Server.GetFriends(player, response => { 
      ShowFriendList(response.friends); 
     }); 
    } 

    private void ShowFriendList(List<Friend> friends) 
    { 
     this.friendCount.text = friends.Count.ToString(); 
     // Display friend entries... 
    } 
} 

応答と制御をFriendsUIに返します。

これは通常正常に動作します。しかし、デリゲートが呼び出される前に友人のUI画面を閉じた場合、そのコンポーネントの - とそのクラス内の他のコンポーネントはすべて破棄され、NPEがアクセスしようとするとスローされます。

これを知っていれば、C#のイベントシステムはこれのためのより良い設計と思いますか? ServerFriendsEventイベントのようなものを公開し、FriendsUIはそれを購読します。 Serverが応答を検証/変換した時点で、イベントが発生します。また、FriendsUIは、それ自身の後にクリーンアップし、スクリプトが添付されたGameObjectが破棄されたときにハンドラの登録を解除する。こうすれば、イベントがServerに発生した時点で、イベントハンドラがFriendsUIで有効でなくなった場合、それは呼び出されません。

私はそれを実装する前に、私の頭の中でこれを実行しようとしています。なぜなら、やや大きなリファクタリングになるからです。私は、人がそれが良い道だと思うかどうか、他に良いルートがあるかどうか、道に沿って陥る可能性のある落とし穴があるかどうかについてのガイダンスを探しています。

ありがとうございます。

+0

UnityEventを使うことを学ぶ。それは容易ではありません。 http://stackoverflow.com/a/36249404/294884 – Fattie

+0

Joeさん、ありがとうございます。 UnityEventシステムは、過度に冗長なようですが、それはおそらく行く方法です。例えば、私が考えているように、 'UnityEvent 'を拡張した 'Server'クラスに' FriendsResponseEvent'クラスを公開する必要があります。また、 'Server'の' FriendsResponseEvent'プロパティを宣言してインスタンス化する必要があります。次に、私の 'FriendsUI#OnStart'メソッドに' Server.FriendsResponseEvent.AddListener(ReceivedFriends) 'を追加します。このパターンは、 'Server'が発生させようとしているすべてのイベントで発生する必要があります。それとももっと簡潔な方法がありますか? – Monkey34

+0

テストでは、(1)サーバクラスに 'public UnityEvent teste;'と入力します。 (2)そのクラスのどこかで(例、接続が完了したら) 'teste.Invoke()'に行きます。最後に、(3)サーバークラスのInspectorを確認します。今すぐあなたが "テストする"(あなたがそのようにしたい数だけ接続する)ものをDRAGしてください。 – Fattie

答えて

2

単にC#delegateeventを使用してください。イベントを購読するためにサーバーから友だちリストを受け取ったときに通知を受けたい各スクリプトを作成します。

public class FRIENDSAPI : MonoBehaviour 
{ 
    public delegate void friendListReceived(List<FRINDSINFO> _friends); 
    public static event friendListReceived onFriendListReceived; 

    //Function that gets friends from the network and notify subscribed functions with results 
    public void getFriends() 
    { 
     StartCoroutine(getFriendsCoroutine()); 
    } 

    private IEnumerator getFriendsCoroutine() 
    { 
    List<FRINDSINFO> friendsFromNetwork = new List<FRINDSINFO>(); 

    /* 
    NETWORK CODE 

    //FILL friendsFromNetwork with Result 
    friendsFromNetwork.Add(); 

    */ 


    //Make sure a function is subscribed then Notify every subscribed function 
     if (onFriendListReceived != null) 
     { 
     onFriendListReceived(friendsFromNetwork); 
     } 

    yield return null; 
    } 
} 

は、その後、あなたの FriendsUIクラスで、 Start()機能に加入し OnDisable()機能に退会します。 OnEnable()の機能では通常購読しますが、時には に初期化されないために機能しないことがあります。 Start()関数でそれを行うのは、 の修正です。

public class FriendsUI: MonoBehaviour 
{ 

    void Start() 
    { 
     //Subscribe 
     FRIENDSAPI.onFriendListReceived += onFriendsReceived; 

     FRIENDSAPI friendAPI = gameObject.GetComponent<FRIENDSAPI>(); 
     friendAPI.getFriends(); //Get friends 
    } 

    public void OnDisable() 
    { 
     //Un-Subscribe 
     FRIENDSAPI.onFriendListReceived -= onFriendsReceived; 
    } 

    //Call back function when friends are received 
    void onFriendsReceived(List<FRINDSINFO> _friends) 
    { 
     //Do Whatever you want with the result here(Display on the Screen) 
    } 
} 
+0

コメントありがとうございます。最終的にイベントを使用する場合、これが私が行くルートになるようです。しかし、人々が運営したいと思っていた主な事柄は、イベントがこのタイプのシナリオで最も効果的だと思ったアプローチだった場合、または代理人(つまり自分の現在のルートを変更する)を達成する方法がある場合や、アプローチが私にはうってつけです。 – Monkey34

+1

@ Monkey34あなたは 'Action'を使うこともできますし、あなた自身で行うこともできますが、重要なことは、購読しているクラスが破壊/無効になるたびに退会することを確認することです。そうしなければ、別の問題が生じるでしょう。 – Programmer

関連する問題