2009-08-16 12 views
1

アップルと私が見た多くの例によると、KVO/KVCを使用して自分自身を観察することは問題ありません。 forKeypath:オプション:コンテキスト:オブジェクトのinitメソッド、ラで:また、同じ情報源によると、それはaddObserverを使用してこれを設定する問題ではないaddObserverを使用した奇妙な問題:forKeypath:options:context:initメソッド

- (id)init 
{ 
    self = [super init]; 
    if (self) { 
    [self addObserver:self 
       forKeyPath:@"selected" 
        options:NSKeyValueObservingOptionNew 
        context:NULL]; 
    } 
    return self; 
} 

残念ながらいくつかの理由で、私のオブザーバメソッドはしていません私がそこでそれをするときに呼び出される。私は別の方法にaddObserver呼び出しを移動し、呼び出し元のメソッドでそのメソッドを呼び出す場合:

MyObject *newObj = [[MyObject alloc] init]; 
[newObj setupObservers]; 

その後、すべての罰金です。これはNSImageViewのサブクラスなので、ここには「awakeFromNib」型の選択肢はありません...私はここで私の頭を傷つけています。私は何か明白なものを欠いていると確信しています。 initメソッドではKVOを自分自身で動作させないようにしていますが、私はここに何かヒントを与えてくれるドキュメントには何も見つかりませんでした。

私には分かりません。

+1

これはあなたの質問に対する回答ではありませんが、NULLではなく、常にコンテキストの値として一意のポインタを渡す必要があります。 NSImageView、またはクラスのいくつかのサブクラスが自分の選択したプロパティを観察し始めると、両方ともNULLをこの方法で使用するとすべてがうまくいかなくなります。 –

答えて

0

は、私はそのような制限があるか否かわからないんだけど、あなたはawakeFromNibを持っていない場合でも、あなたのinitメソッドでは、実行ループにsetupObserversを追加して作成することができます

[[NSRunLoop currentRunLoop] 
    performSelector:@selector(setupObservers) 
    target:self 
    argument:nil 
    order:1 
    modes:NSDefaultRunLoopMode]; 
+1

確かに、それはうまくいくことはほとんど疑いがありますが、それはハックのように見えませんか?また、そういうことをやっていると、なぜ最初にうまくいかないのかが分かりません。つまり、プログラミング習慣が悪いということについて私が気づいていない情報が残っているということです。私は本当にそうしているから、彼らがやっているやり方で仕事をしたいと思っています...あなたは知っていますか? – Chronor

+0

performSelector:afterDelayとその変形は、簡単に悪用される強力なメソッドです。これは虐待です。セレクタが最終的に起動したときとセレクタが最後までの間に選択が変更されたらどうなりますか?私たちが観察をやめさせる何かをするなら、どうしたらうまくいかないのでしょうか?問題を「修正」するには、この方法を使わないでください。それには大きな用途がありますが、これはただのものではありません。 –

+0

@Jon、@Chronor:これは間違いなくハックです。それはちょうど働くハッキングかもしれません、そして時にはそれは十分です...あなたが 'setupObservers'を自分で呼び出すことを"余裕 "できるなら、それは明らかに優れています。 –

0

これは私がunderstない...そう それは好きではないです、ここで任意の 「awakeFromNib'型代替 があります、

NSImageViewのサブクラスでありますそしてこの点。あなたはNIBにこのオブジェクトを作成しているのですか? NIBがこのオブジェクトを作成している場合は、-awakeFromNibが呼び出されます。最初に設定する必要があるのは、-initが実際に実行されているかどうかです(NSLog()を使用)。何も起こらないときは、通常、コードが実行されなかったことを意味します。

+0

おそらく私はもっとはっきりしていたはずです。はい、NSImageViewのサブクラスですが、別のアクションの一部としてコード内でインスタンス化しているものです。私はそれを既存のウィンドウ内のカスタムビューにサブビューとして追加します。したがって、awakeFromNibはありません。混乱させて申し訳ありません。 – Chronor

4

おそらく、あなたのケースでは、-initが呼び出されないという問題があります。-initWithCoder:isです。

すべてのCocoaクラスには、「指定初期化子」と呼ばれる一連のinitメソッドがあります。インスタンス化されるごとに、各オブジェクトは継承ツリーの各クラスの指定された初期化子のうちの1つだけを通過することが保証されます。

クラスをサブクラス化して初期化を行う場合は、スーパークラスの指定された初期化子をすべてオーバーライドする必要があります。

NSImageViewの設計された初期化子は、-initWithCoder:とinitWithFrame:です。 initではなく、2つをオーバーライドします。その後、

static void *MyPrivateObservationContext = (void*)@"MyPrivateObservationContext"; // we assume MyPrivateObservationContext is a unique name, I use something of the form ClassNamePropertyObservationContext

-[obj add....... context:&MyPrivateObservationContext]; 

その後

-(void)observeValueForKeyPath:....context:c; 
{ 
    if (c == &MyPrivateObservationContext) { 
     // do work 
    } else { 
     [super observeValueForKeyPath:...]; 
    } 
} 
+0

また、 "選択された"は、NSImageViewのサブクラスに追加するメソッドがあまりにも一般的です。 NSControlまたはNSImageViewに選択したメソッドを追加することをCocoaが決定した場合はどうなりますか?セマンティクスはおそらくあなたのものと一致せず、悪いことが起こります。あなたが "選択された"よりもあなたの使用のより具体的な記述を思い付くことができるかどうかを見てください。そうでない場合は接頭辞を使用してください。 – user96459

+0

誰かが私を見つけて、私は自分自身を打つことができます。 initがそのクラスの指定された初期化子ではないという事実をどうして逃すことができますか?もちろんそれはそれであり、適切な変更を問題を解決するものにしました。私に思い出させてくれてありがとう! はい、私は、「選択された」がおそらく最も良いプロパティ名ではないことに同意します。私は何か別のものを考え出します。ありがとう... – Chronor

2

コンテキスト・ポインタについては、好ましい方法でありますまだ初期化されていないオブジェクト(init関数はあなたが自己を返す前にオブザーバー)。代わりに- (void)viewDidLoad

[self addObserver:self 
     forKeyPath:@"selected" 
      options:NSKeyValueObservingOptionNew 
      context:NULL]; 

:以下のコードを移動します。それはうまくいくだろう。

0

に基本的には、KVO通知を追加しようとしている。

+0

私はこれを考えていました。しかし、self = [super init]がinitの先頭で呼び出された場合、後でinitメソッドのオーバーライドの任意の時点でselfがオブザーバとして追加される準備ができているということは本当ですか? – eddy

+0

しかし、ポイントは代わりにkeyPathです。オブザーバを追加する前に、keyPathを初期化する必要があります。あなたのケースでは、BOOLは初期化理論がうまくいかないと思うようです。それをヘッダーに_selectedとして宣言し、selected = _selectedとして@synthesizeプロパティを選択してみてください。それは仕事をするはずです。 – DennyLou