2011-07-11 12 views
3

カスタムジェスチャーを開発するときに、デバッグ/トレースメッセージの状態名の表が必要です。この宣言とその使用法は何が間違っていますか?iPhone/XCodeで静的な文字列テーブルを定義する方法は?

static NSDictionary *dictStateNames = nil; 

@implementation MyCustomGesture 


@synthesize state; 

+(void)initStateNames { 
    if (dictStateNames == nil) { 
     dictStateNames = [NSDictionary dictionaryWithObjectsAndKeys: 
          @"StateBegan", [NSNumber numberWithInt:UIGestureRecognizerStateBegan], 
          @"StateCancelled", [NSNumber numberWithInt:UIGestureRecognizerStateCancelled], 
          @"StateChanged", [NSNumber numberWithInt:UIGestureRecognizerStateChanged], 
          @"StateEnded", [NSNumber numberWithInt:UIGestureRecognizerStateEnded], 
          @"StateFailed", [NSNumber numberWithInt:UIGestureRecognizerStateFailed], 
          @"StatePossible", [NSNumber numberWithInt:UIGestureRecognizerStatePossible], 
          @"StateRecognized", [NSNumber numberWithInt:UIGestureRecognizerStateRecognized], 
          nil]; 
    } 
} 

-(id) init { 
    self = [super init]; 
    if (self) { 
     [MyCustomGesture initStateNames]; 
     state = UIGestureRecognizerStatePossible; 
    } 
    return self; 
} 

-(id) initWithTarget:(id)target action:(SEL)action { 
    self = [super initWithTarget:target action:action]; 
    if (self) { 
     [MyCustomGesture initStateNames]; 
     state = UIGestureRecognizerStatePossible; 
    } 
    return self; 
} 

+(NSString*) stateName: (UIGestureRecognizerState) state { 
    NSString *retName = [dictStateNames objectForKey:[NSNumber numberWithInt:state]]; 
    if (retName == nil) { 
     return [NSString stringWithFormat:@"Unknown state (%@)", state]; 
    } else { 
     return retName; 
    } 
} 

-(NSString*) currentStateName { 
    return [MyCustomGesture stateName:state]; 
} 

-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
    NSLog(@"%s (%@): %@", __FUNCTION__, [self currentStateName], event); 
} 

答えて

6

オブジェクトへの参照を静的変数に格納するときは、オブジェクトが解放されないようにする必要があります。したがって、retainメッセージを送信するか、簡易作成メソッドの代わりにallocを使用して作成することができます。たとえば:あなたはObjective-Cの開発者が書く一般的に表示されますので、

dictStateNames = [[NSDictionary dictionaryWithObjectsAndKeys: 
         // List of objects and keys... 
         nil] retain]; 

またはこの...

dictStateNames = [NSDictionary alloc] initWithObjectsAndKeys: 
         // List of objects and keys... 
         nil]; 

また、あなたは、単一の方法にあなたのstateNamesゲッターと初期化コードを合体することができますこのような方法:新しい辞書を毎回作成されますので、

+ (NSDictionary *)stateNames 
{ 
    static NSDictionary *stateNames; 

    if (stateNames == nil) { 
     stateNames = [NSDictionary alloc] initWithObjectsAndKeys: 
         // List of objects and keys... 
         nil]; 
    } 

    return stateNames; 
} 

その方法は、インスタンスメソッドでそれを呼び出す必要は、とにかく間違っていると思われる(ありませんインスタンスが初期化され、別の方法で処理しない限り、前のインスタンスがリークされます)。別の(無関係な)ノートで

、次のようにあなたのinit方法を書き換える考える:

- (id)init 
{ 
    return [self initWithTarget:nil action:NULL]; 
} 
+0

これは正しい答えです。あなたのコードmobibobの問題は、jlehrのように、deallocされているということです。それを正しく保持すると、問題が解決します。 –

+0

これは理にかなっています。私はそれが基本的に間違っていることを知っていましたが、ポインタが「悪くなっていた」(割り当てが解除された)場所を特定できませんでした。 BTW - あなたが示唆しているようにゲッター関数内でコードを初期化するように既に移動しました。今度はinitと合体してください。それはあなたの提案ですべて記録され、正しく動作し、クラッシュしません。 – mobibob

+0

なぜ 'stateNames'は' NSDictionary * 'ではなく 'void'を返しますか? – bcattle

3

[NSDictionary dictionaryWithObjectsAndKeys]は最初それがそこに少し後方に思われるが、その鍵(メソッド名が示唆するように)、続いてオブジェクトをとります。

+0

、私はそれがAPIをされmindbending方法がなければ、私はもう少しのObjective-Cのようにしたい気持ちを持っています。たくさんの冗長なものが分かりやすいと思うでしょうが、(NSNumber fromInt: 'やNSNumber withInt:'ではなくNSNumber numberWithInt: ')単純な例として、冗長で反復的です。多くの場合、奇妙に巻き込まれています(しかし、それは別の議論の話題です)。 – JAB

+1

異なるクラスのジェネリックメソッド名は、異なるクラスに対して同じように動作しない限り、素晴らしい考えではありません。セレクタ(メソッド名)は、特定の点でグローバルな名前空間に存在します。 –

+0

多分私は私の質問と説明で明確ではなかった。私はNSDictionaryとこれらの議論された方法を理解していますが、私が求めているのは、保存と参照の範囲です。私のコードは "touchesBegan"に対して期待通りに動作しますが、辞書にアクセスしようとする "touchesMoved"でクラッシュします。 MyCustomGestureのすべてのインスタンスで参照されている静的な辞書を宣言する方が良い(適切な)方法がありますか? NSLogでは、現在の状態の名前を検索し、それを辞書からの文字列として表示する必要があることに注意してください。 – mobibob