質問
カードを使用するゲームを作成しています。 ペン先に1つのインスタンスを持つAppControllerクラスがあります。 AppControllerインスタンスには、wordListというNSArrayインスタンス変数があります。 初期化時に、AppControllerのnibのインスタンスは新しいGameCardを生成します。 すべてのゲームカードには、AppControllerのリストからランダムに選択された5つの単語を含む単語の配列があります。 リストが大きいため、一度だけメモリに読み込むようにします。そのため、シングルトンクラスとして、AppControllerのインスタンスを1つだけ必要とします。 AppController内から新しいGameCardが作成されるたびに、同じシングルトンインスタンスにアクセスしてワードリストを取得する必要があります。 基本的に、GameCardを作成するシングルトンAppControllerが必要です。各GameCardには元のAppControllerへの参照があります。 これを実装する方法がわかりません。説明がわかりにくい場合は申し訳ありません。
オンラインで見つけたコード例は次のとおりです( http://numbergrinder.com/node/29 )
+ (AppController *)instance
{
static AppController *instance;
@synchronized(self) {
if(!instance) {
instance = [[AppController alloc] init];
}
}
return instance;
}
しかし、以下のコードを使用してGameCardインスタンスで何かを実行しようとすると、アプリケーションの起動に永遠に時間がかかり、Xcodeは99797スタックフレームをロードしていることを通知しました。
AppController *controller = [AppController instance];
解決
それは無限ループのように聞こえます。 -[AppController init]が+ [AppControllerインスタンス]を呼び出していないことを確認してください。
他のヒント
すべてのカードにアプリコントローラーへの参照が必要な理由
単語にアクセスするだけであれば、各カードが単語を直接所有する方が簡単です。 initWithWords:
という名前の新しいメソッドをGameCardクラスの指定イニシャライザーにします。 5つの単語の配列を使用して各カードを初期化し、カードがその寿命の間その配列を所有するようにします。
アプリコントローラーへのカードの参照を削除すると、Tomが鋭く検出した無限ループが解決されます。
また、一度に2枚のカードに単語が表示されない場合は、アプリコントローラーのGreat Big Array of Wordsから描画するとき、およびカードを破棄するときに、そのことを考慮に入れることを忘れないでください将来のカードのために山に。)
あなたは正しい道を進んでいるようです。ただし、nibファイルにシングルトンへの参照を配置しようとしたことはありません。データのコピーを保持する別のシングルトンクラス(DataManager、おそらく?)を作成し、AppControllerのインスタンス内から呼び出して単語を取得することができます。
(Stuの投稿でシングルトンのコードを使用して)ペン先にシングルトンを入れると、うまくいくことがあります。がんばって!
init
メソッド内からクラスの instance
メソッドを呼び出しているようです。次のようなものを試してください:
static AppController* _instance = nil;
- (id)init
{
// depending on your requirements, this may need locking
if( _instance ) {
[self release];
return _instance;
}
if( (self = [super init]) ) {
_instance = [self retain];
// do your initialization
}
return self;
}
+ (AppController*)instance
{
if( _instance ) return _instance;
else return [[AppController alloc] init];
}
これにより、AppControllerの1つのインスタンスのみが使用可能になり、 instance
クラスメソッドを介してコピーを取得するだけでなく、それを安全に割り当てることができます。スレッドセーフではないため、複数のスレッドからアクセスする場合は、 _instance
のチェックをロックする必要があります。
AppController / AppDelegateを作成する通常の方法は、カスタムNSObjectをMainMenu / MainWindow.xibファイルに追加することです。クラスをAppControllerに設定します。 UIApplication / NSApplicationデリゲート参照をAppControllerオブジェクトにリンクします。その後、次のいずれかで単一のAppControllerを取得できます
(AppController*)[NSApp delegate];
または
(AppController*)[[UIApplication sharedApplication] delegate];
アプリケーションの起動時に作成されるため、alloc / initで作成する必要はありません。誰も別のものを作成しようとしないので、シングルトンにすることを心配する必要はありません。また、UIApplication / NSApplicationオブジェクトのデリゲートになるため、アクセス方法について心配する必要はありません。
以上のことは、単語の配列を保持するグローバル変数が必要な場合、AppControllerを忘れて、配列を保持/読み取る新しいシングルトンオブジェクトを作成することです。その場合、必要なのは
だけです。+ (NSArray *)sharedWordListArray
{
static NSArray *wordList;
if( !wordList ) {
wordList = [[NSMutableArray alloc] init];
// read array
}
return wordList;
}
本当にスレッドセーフが必要な場合は、スレッドを開始する前に、アプリデリゲートのapplicationDidFinishLaunching:メソッドから[WordList sharedWordListArray]を呼び出すか、ロードを後で延期したい場合はNSLockを追加します。ユーザーが後でアクションを実行したときに予期せずに、プログラムの開始時にロード時間がヒットしました。