objective CオブジェクトにremoveObservers:を伝えるように指示すると、キーパスがあり、そのキーパスが登録されていない場合、それは悲しみを解き放ちます。好む -
「キーパス「theKeyPath」のオブザーバーは、オブザーバーとして登録されていないため、削除できません。」
オブジェクトに登録されたオブザーバーがあるかどうかを判断する方法がありますので、私はこれを行うことができます
if (object has observer){
remove observer
}
else{
go on my merry way
}
RemoveObserver呼び出しをキャッチしよう
@try{
[someObject removeObserver:someObserver forKeyPath:somePath];
}@catch(id anException){
//do nothing, obviously it wasn't attached because an exception was thrown
}
本当の問題は、それを観察しているかどうかわからない理由です。
監視されているオブジェクトのクラスでこれを実行している場合は、停止します。それを観察しているものは何でもそれを観察し続けることを期待しています。知らないうちにオブザーバーの通知を遮断した場合、問題が発生することを期待してください。より具体的には、以前に観測されたオブジェクトから更新を受信しないため、観測者の状態が古くなることを期待してください。
監視しているオブジェクトのクラスでこれを実行している場合、監視しているオブジェクトを覚えておいてください(または、1つのオブジェクトのみを監視している場合は、監視しているかどうか)。これは、観測が動的であり、他の点では無関係な2つのオブジェクト間で行われることを前提としています。オブザーバーがオブザーバーを所有している場合は、オブザーバーを作成または保持した後にオブザーバーを追加し、オブザーバーをリリースする前にオブザーバーを削除します。
オブザーバーとしてのオブジェクトの追加と削除は、通常、オブザーバーのクラスで発生し、監視対象のオブジェクトでは発生しません。
FWIW、 [someObject observationInfo]
は、nil
にオブザーバーがない場合、someObject
のようです。しかし、文書化されていないので、この動作は信用しません。また、特定のオブザーバーを取得するためのobservationInfo
の読み方がわかりません。
これを行う唯一の方法は、オブザーバーを追加するときにフラグを設定することです。
オブジェクトにオブザーバーを追加するとき、次のようにNSMutableArray
に追加できます:
- (void)addObservedObject:(id)object {
if (![_observedObjects containsObject:object]) {
[_observedObjects addObject:object];
}
}
オブジェクトを観察したくない場合は、次のようなことができます。
for (id object in _observedObjects) {
if ([object isKindOfClass:[MyClass class]]) {
MyClass *myObject = (MyClass *)object;
[self unobserveMethod:myObject];
}
}
[_observedObjects removeAllObjects];
覚えていない場合は、単一のオブジェクトを観察しない場合は、_observedObjects
配列:
- (void)removeObservedObject:(id)object {
if ([_observedObjects containsObject:object]) {
[_observedObjects removeObject:object];
}
}
[someObject observationInfo]
オブザーバーがいない場合はnil
を返します。
if ([tableMessage observationInfo] == nil)
{
NSLog(@"add your observer");
}
else
{
NSLog(@"remove your observer");
}
私の意見では-これはretainCountメカニズムに似ています。現在、あなたがあなたのオブザーバーを持っていることを確信することはできません。以下をチェックしても:self.observationInfo-将来オブザーバーがいる/いないことを確実に知ることはできません。
retainCountのように。たぶんobservationInfoメソッドはその種の役に立たないわけではありませんが、デバッグ目的でのみ使用しています。
そのため、結果として-メモリ管理のように行うだけです。オブザーバーを追加した場合は、必要ないときに削除してください。 viewWillAppear/viewWillDisappearなどのメソッドを使用するように。例えば:
-(void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self addObserver:nil forKeyPath:@"" options:NSKeyValueObservingOptionNew context:nil];
}
-(void) viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self removeObserver:nil forKeyPath:@""];
}
そして、いくつかの特定のチェックが必要です-オブザーバーの配列を処理する独自のクラスを実装し、それをチェックに使用します。
オブザーバーパターンの要点は、観察対象のクラスを「封印」できるようにすること、つまり、観察対象のクラスを知らないか気にしないことです。明示的にこのパターンを破ろうとしています。
どうして?
あなたが持っている問題は、あなたがそうでないときにあなたが観察されていると仮定しているということです。このオブジェクトは観測を開始しませんでした。クラスでこのプロセスを制御できるようにする場合は、通知センターの使用を検討する必要があります。そうすることで、クラスはデータをいつ観察できるかを完全に制御できます。したがって、誰が見ているかは気にしません。
私はキャッチキャッチソリューションのファンではないので、ほとんどの場合、そのクラス内の特定の通知に対してサブスクライブおよびサブスクライブ解除メソッドを作成します。たとえば、次の2つのメソッドは、オブジェクトをグローバルキーボード通知にサブスクライブまたはサブスクライブ解除します。
@interface ObjectA : NSObject
-(void)subscribeToKeyboardNotifications;
-(void)unsubscribeToKeyboardNotifications;
@end
これらのメソッド内では、次のようにサブスクリプションの状態に応じてtrueまたはfalseに設定されるプライベートプロパティを使用します。
@interface ObjectA()
@property (nonatomic,assign) BOOL subscribedToKeyboardNotification
@end
@implementation
-(void)subscribeToKeyboardNotifications {
if (!self.subscribedToKeyboardNotification) {
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(onKeyboardShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(onKeyboardHide:) name:UIKeyboardWillHideNotification object:nil];
self.subscribedToKeyboardNotification = YES;
}
}
-(void)unsubscribeToKeyboardNotifications {
if (self.subscribedToKeyboardNotification) {
[[NSNotificationCenter defaultCenter]removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter]removeObserver:self name:UIKeyboardWillHideNotification object:nil];
self.subscribedToKeyboardNotification = NO;
}
}
@end
Adamの答えに加えて、このようなマクロを使用することを提案したいと思います。
#define SafeRemoveObserver(sender, observer, keyPath) \
@try{\
[sender removeObserver:observer forKeyPath:keyPath];\
}@catch(id anException){\
}
使用例
- (void)dealloc {
SafeRemoveObserver(someObject, self, somePath);
}