如果你告诉一个目标c对象removeObservers:对于一个密钥路径并且该密钥路径尚未注册,它会破坏sads。喜欢 -
'无法删除关键路径“theKeyPath”的观察者,因为它未注册为观察者。'
有没有办法确定一个对象是否有一个注册的观察者,所以我可以这样做
if (object has observer){
remove observer
}
else{
go on my merry way
}
答案 0 :(得分:310)
尝试捕捉removeObserver调用
@try{
[someObject removeObserver:someObserver forKeyPath:somePath];
}@catch(id anException){
//do nothing, obviously it wasn't attached because an exception was thrown
}
答案 1 :(得分:37)
真正的问题是为什么你不知道你是否在观察它。
如果你在观察对象的类中这样做,请停止。无论观察什么,它都希望继续观察它。如果你在不知情的情况下切断了观察者的通知,那么期待事情就会破裂;更具体地说,期望观察者的状态变得陈旧,因为它没有从以前观察到的对象接收更新。
如果您在观察对象的类中执行此操作,只需记住您正在观察的对象(或者,如果您只观察一个对象,是否正在观察它)。这假设观察是动态的,并且在两个不相关的对象之间;如果观察者拥有观察者,只需在创建或保留观察者后添加观察者,并在释放观察者之前移除观察者。
作为观察者添加和删除对象通常应该发生在观察者的类中,而不是在观察对象中。
答案 2 :(得分:25)
FWIW,如果nil
没有任何观察员,[someObject observationInfo]
似乎是someObject
。但是,我不相信这种行为,因为我没有看到它记录在案。另外,我不知道如何阅读observationInfo
以获得特定的观察员。
答案 3 :(得分:5)
当您向对象添加观察者时,可以将其添加到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];
}
}
答案 4 :(得分:4)
执行此操作的唯一方法是在添加观察者时设置标记。
答案 5 :(得分:3)
在我看来 - 这与retainCount机制类似。你无法确定目前是否有观察者。 即使您检查: self.observationInfo - 您也无法确定将来是否有/将不会有观察员。
与 retainCount 类似。也许 observationInfo 方法不是那么无用,但我只在调试目的中使用它。
因此,您必须像在内存管理中那样执行此操作。如果添加了观察者 - 只需在不需要时将其删除即可。喜欢使用viewWillAppear / viewWillDisappear等方法。 E.g:
-(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:@""];
}
你需要一些特定的检查 - 实现你自己的类来处理一组观察者并用它来进行检查。
答案 6 :(得分:3)
[someObject observationInfo]
会返回nil
。
if ([tableMessage observationInfo] == nil)
{
NSLog(@"add your observer");
}
else
{
NSLog(@"remove your observer");
}
答案 7 :(得分:2)
观察者模式的重点是允许观察到的类被“密封” - 不知道或不关心它是否被观察到。您明确试图打破这种模式。
为什么?
你遇到的问题是你假设你没有被观察。这个对象没有开始观察。如果您希望班级控制此过程,则应考虑使用通知中心。这样,您的班级可以完全控制何时可以观察数据。因此,它并不关心谁在观看。
答案 8 :(得分:1)
我不是那种尝试捕获解决方案的粉丝所以 我大部分时间都在做的是,我为该类中的特定通知创建了一个订阅和取消订阅方法。例如,这两个方法将对象描述或取消订阅到全局键盘通知:
@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
在这些方法中,我使用私有属性,根据订阅状态设置为true或false,如下所示:
manage.py celerybeat
答案 9 :(得分:0)
除了亚当的答案,我还建议像这样使用宏
#define SafeRemoveObserver(sender, observer, keyPath) \
@try{\
[sender removeObserver:observer forKeyPath:keyPath];\
}@catch(id anException){\
}
用法示例
- (void)dealloc {
SafeRemoveObserver(someObject, self, somePath);
}