gpt4 book ai didi

ios - 当 removeObserver 用于 Integer 属性时崩溃?

转载 作者:可可西里 更新时间:2023-11-01 05:41:38 24 4
gpt4 key购买 nike

我创建了一个带有 XIB 的 CustomView:UIView,为 NSInteger 属性加载和添加观察者,如下所示:

//自定义 View .h

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

//自定义 View .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

但是当 removeObserver 时,App 崩溃了:

*** 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 属性添加和删除观察者?

提前致谢!

*编辑:我添加我的代码来明确我的问题。请帮忙!

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

最佳答案

这就是发生的事情 - 在您的 viewDidLoad 方法中,您调用了 [[CustomView alloc] init]。这将创建一个新的 CustomView 实例,并对其调用 init。但是,在 init 中,您从 nib 加载一个新实例并将 self 替换为来自 nib 的实例。这会导致您从 alloc 创建并使用 self = [super init]; 设置的实例被释放,因为不再有对它的强引用。由于此实例在调用 commonInit 之前被释放,它从不观察自己的属性,因此将自己作为观察者移除会导致异常。

解决这个问题的一种方法是直接从 View Controller 中的 nib 加载 View ,或者在 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 加载 View 时自动调用。您只需实现它,就可以进行您已经在 init 中进行的设置。还要确保你的 dealloc 是这样实现的:

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

关于ios - 当 removeObserver 用于 Integer 属性时崩溃?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15694226/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com