0

アプリにシングルトンを実装していますが、View Controller を切り替えるときに問題が発生しました。

私のアプリは、1 つのビュー コントローラー MainMenu で開始し、メニュー選択が行われると Game ビュー コントローラーに切り替わります。ゲームのオブジェクト マネージャー (World と呼ばれる) である Game VC にシングルトン クラスがあります。MainMenu でのメニュー選択に基づいてコンテンツをロードします。MainMenu VC に問題なくロードして終了できます。シングルトンは正常に動作します。MainMenu から再度選択すると (MainMenu VC から Game VC に移動)、NSAssert の原因でアプリがクラッシュし、シングルトン World が 2 回目の割り当てを行わないようにします。これは意図的なものです。

シングルトンを再初期化しようとせずにゲーム VC に戻すにはどうすればよいですか?

[[world alloc] init]基本的に、ゲーム VC の init メソッドの行をスキップしたいと考えています。これを適切に行う方法がわかりません...初めて(Worldが存在しない場合)またはその後(Worldがすでにシングルトンとして存在する場合)に処理できる必要があります。私は試しましたが、うまくいきif (!world)ません。

これも疑問です...シングルトンを適切な場所に実装しましたか? 代わりに MainMenu に入れる必要がありますか? 2 つの VC を切り替えるときに、シングルトンを再初期化/再割り当てしようとするのを避けたいだけです。

[self.view removeFromSuperview]; これで問題が解決する場合は、 Should I do it a different way?を使用してゲーム VC を終了します。

4

2 に答える 2

2

質問が正しく理解できたら、Singleton クラスの作成方法を知りたいですか? 最近の一般的な方法は、次のように grand-central-dispatch を使用することです。

+ (MyViewController*)shared
{
    static dispatch_once_t onceToken;
    static MyViewController* instance;

    dispatch_once(&onceToken, ^
    {
        instance = [[[self class] alloc] init];
    });
    return instance;
}

その後、次の方法でインスタンスにアクセスできます。

[MyViewController shared];

grand-central-dispatch の前は、クラスに静的インスタンスを配置し、共有アクセサーを呼び出すときにそれが nil かどうかを確認するという手法でした。また、スレッドセーフを確保するために、アクセサーを @synchronized(self) でラップする必要があります。GCD 方式は、パフォーマンスが少し向上することが示されています。

そうは言っても、意志のあるシングルトンを使用することをお勧めします。それらがアンチパターンと見なされる理由を調査し、代替手段として依存性注入を調査します。

依存性注入とシングルトン

シングルトンの問題は、密結合につながる可能性があることです。航空会社の予約システムを構築しているとしましょう。予約コントローラーは次のものを使用する場合があります。

id<FlightsClient>

コントローラー内でそれを取得する一般的な方法は次のとおりです。

_flightsClient = [FlightsClient sharedInstance];

シングルトンを使用してクラスをテストするには、同時にシングルトンをテストする必要があります。特にアプリケーションが複雑になると、これは難しくなる可能性があります。クラス A をテストし、クラス B に依存し、クラス C に依存し、... に依存することを想像してみてください。

別の方法として、依存性注入を使用する方法があります。これは単に、初期化子またはプロパティ セッターを使用して予約クライアントを予約コントローラーに渡すことを意味します。これは手動で行うことも、ライブラリを使用することもできます。手動で行う場合は、シングルトンを宣言しても問題ありませんが、最上位のアセンブリ クラスがインスタンスを保持できるため、おそらくその必要はありません。

シングルトンに対するこの代替アプローチを使用することにより、クラスは疎結合になり、テストと保守が容易になります。(そして、依存性注入を使用すると、同様に派手な名前が付けられます;))

Spring に基づいて依存性注入ライブラリを作成しました: https://github.com/jasperblues/spring-objective-c

于 2013-01-15T06:49:45.720 に答える
1

私が考えていたように、実際にシングルトンの初期化を MainMenu ビューコントローラーに移動することで、これを解決できました。私の設計でinitは、その VC はアプリの起動時に 1 回だけ呼び出されますinitが、ゲーム VC のカスタム メソッドは切り替えるたびに呼び出されます。

それが私が使用すべき最適な設計であるかどうかはわかりませんが、今のところ機能しています。

于 2013-01-15T08:33:48.970 に答える