4

そのような NSInteger プロパティの XIB、load、および addObserver を使用して CustomView:UIView を作成します。

//CustomView.h

@interface CustomView : UIView
    @property (nonatomic) NSInteger inputStateControl;
@end

//CustomView.m

static void *kInputStateControlObservingContext = &kInputStateControlObservingContext;
@implementation CustomView
- (id)init
{
    self = [super init];
    if (self) {
        // Initialization code
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"CustomView" owner:self options:nil];
        self = [nib objectAtIndex:0];
        //
        [self commonInit];
    }
    return self;
}

-(void)commonInit{
[self addObserver:self forKeyPath:@"inputStateControl" options:NSKeyValueObservingOptionOld context:kInputStateControlObservingContext];
}

#pragma mark Observer
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {

    if ( context == kInputStateControlObservingContext ) {
        NSInteger oldState = [[change objectForKey:NSKeyValueChangeOldKey] integerValue];
        if ( oldState != self.inputStateControl ) {
            NSLog(@"CONTEXT change %i to %i",oldState,self.inputStateControl);
        }
    }
    else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

-(void)dealloc{
    [self removeObserver:self forKeyPath:@"inputStateControl"];
//    [self removeObserver:self forKeyPath:@"inputStateControl" context:kInputStateControlObservingContext];
}

@end

dealloc で removeObserver をコメントアウトすると、すべて正常に動作します。ログは次のとおりです。

CONTEXT change 0 to 2

しかし、Observer を削除すると、アプリがクラッシュします。

*** Terminating app due to uncaught exception 'NSRangeException', reason: 'Cannot remove an observer <Keyboard 0x6a8bcc0> for the key path "inputStateControl" from <Keyboard 0x6a8bcc0> because it is not registered as an observer.'

コメントが CustomView.xib をロードしてもクラッシュしませんが、XIB なしでは何も起こりません。私のコードで何が問題になっていますか?

カスタムXibを使用してCustomView内のNSIntegerプロパティのObserverを追加および削除する方法は?

前もって感謝します!

*編集:質問を明確にするためにコードを追加します。助けてください!

https://github.com/lequysang/github_zip/blob/master/CustomViewKVO.zip

4

4 に答える 4

3

これが何が起こっているかです - あなたの viewDidLoad メソッドで、 を呼び出します[[CustomView alloc] init]。これにより、新しい CustomView インスタンスが作成され、それが呼び出さinitれます。ただし、 ではinit、nib から新しいインスタンスをロードし、nib のインスタンスに置き換えselfます。allocこれにより、から作成してセットアップしたインスタンスself = [super init];は、それに対する強い参照がなくなるため、割り当てが解除されます。このインスタンスは を呼び出す前に割り当てが解除されるcommonInitため、自身のプロパティを監視することはなく、オブザーバーとして自分自身を削除すると例外が発生します。

これを修正する 1 つの方法は、View Controller の nib からビューを直接ロードするか、CustomView でクラス メソッドを作成することです。

NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"CustomView" owner:nil options:nil];
CustomView *customView = topLevelObjects[0];

そのアプローチを取る場合は、init実装を破棄し、これを行う に置き換えますinitWithCoder:

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        _inputStateControl = 0;
        [self commonInit];
    }

    return self;
}

実装する理由initWithCoder:は、nib からビューをロードするときに自動的に呼び出されるためです。実装するだけで、 ですでに行っているセットアップを実行できるようになりますinit。また、dealloc が次のように実装されていることを確認してください。

-(void)dealloc{
    [self removeObserver:self forKeyPath:@"inputStateControl" context:kInputStateControlObservingContext];
}
于 2013-03-29T02:25:19.123 に答える
1

あなたがしていることがうまくいかない理由は正確にはわかりませんが、オブジェクトにこのように自分自身を観察させるのは悪い考えだと思います。inputStateControl のセッターを明示的に実装し ( setInputStateControl)、そのセッター メソッドでロギングやその他の必要な副作用を実行する必要があります。

于 2013-03-29T00:08:11.070 に答える
0

決して理想的な解決策ではありませんが、削除を try-catch ブロックで囲むと問題が解決します。実際にオブザーバーが登録されていない場合は、削除中に例外を無視しても安全です。主なリスクは、アプリが登録されているという仮定に依存していることです。

于 2013-03-29T00:43:29.510 に答える
0

なぜあなたが問題に直面しているのかわかりません.私が行う最も近道の方法は、deallocでカスタムオブザーバーを「nil」に設定することです;)、しかし、あなたの場合、その近道を使用するには、オブザーバーを追加する必要があります他の方法で。

わかりました、少なくとも私はあなたに言うことができます、あなたのdeallocでは、

-(void)dealloc{
    [[NSNotificationCenter default center] removeObserver: self];
    [self removeObserver:self forKeyPath:@"inputStateControl"];
    //OR
    //If you had create a observer called "temp",then easy way to remove the observer is temp=nil;

}

それでもぶらぶらしている場合は、一時的な解決策として @try @catch ブロックを配置します。オブザーバーは削除されないことに注意してください ;)...

あなたが探していた完璧な答えではありませんが、それは私が思う方法です...幸せなコーディング:-)

于 2013-03-29T02:14:38.667 に答える