Objective c 观察对象的变化w/KVO,上下文指针不';t似乎使用的是void*,但使用的是NSString*
所以我有一个主控制器,Objective c 观察对象的变化w/KVO,上下文指针不';t似乎使用的是void*,但使用的是NSString*,objective-c,key-value-observing,void-pointers,Objective C,Key Value Observing,Void Pointers,所以我有一个主控制器, 在标题内部,我声明了以下内容:void*: static void *kStrokeColorWellChangedContext = &kStrokeColorWellChangedContext; 在实施过程中,我正在处理观察: -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object ch
在标题内部,我声明了以下内容:
void*
:
static void *kStrokeColorWellChangedContext = &kStrokeColorWellChangedContext;
在实施过程中,我正在处理观察:
-(void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void*)context
{
if( [keyPath isEqualToString:@"color"] )
{
if( context == kStrokeColorWellChangedContext )
{
[self setValue:[change objectForKey:@"new"] forKey:@"strokeColor"];
}
}
然后我有一个ViewController,它有这一行,它将MainController作为观察者添加到视图中
[self.strokeColorWell addObserver:self.toolController forKeyPath:@"color" options:NSKeyValueObservingOptionNew context:kStrokeColorWellChangedContext];
因此,当视图的颜色发生变化时,它会通知主控制器,并进入-observeValueForKey:
例程,使用键@“color”
但它无法进入内部if
块,我正在检查上下文
如果我用一个NSString*
替换掉我的void*
,它会像我期望的那样工作
void*
中存储了两个不同的地址,这怎么可能呢
编辑:
也许void*
的值会有所帮助
po kStrokeColorWellChangedContext的结果
:
0x00000001005553e8
-observeValueForKey:
中的po上下文的结果:
0x0000000100555ea0
objc[17775]:方法缓存已损坏。这可能是一条发送给用户的消息
无效对象,或其他地方出现内存错误。
objc[17775]:接收器0x100555ea0,SEL 0x7fff899c8246,isa 0x100555ea0,缓存>0x100555eb0,存储桶0x100566160,掩码0x0,占用0x0
objc[17775]:接收器0字节,存储桶0字节
objc[17775]:选择器“响应选择器:”
抛出的异常可能是一个暗示,但我真的一点都不明白
EDIT2:
p
而不是po
(lldb) p context
(void *) $5 = 0x0000000100555ea0
(lldb) p kStrokeColorWellChangedContext
(void *) $6 = 0x00000001005553e8
请注意,我非常确信我正在调试正确的通知。
原因有二;keyPath
是唯一的,我认为该值是正确的。另外,如果我使用一个NSString*
作为上下文,它对我有效-kStrokeColorWellChangedContext“有”两个地址:它在内存中的位置和它的值,它们都是相同的!因此,在整个程序中,kStrokeColorWellChangedContext
和&kStrokeColorWellChangedContext
应该是可互换的
您是否尝试过单步执行KVO回调并查看/记录context
和kStrokeColorWellChangedContext
的值?和keyPath
?问题在于您将kStrokeColorWellChangedContext
定义为标头中的静态变量。导入该头文件的每个翻译单元(基本上是源文件)都将创建一个按该名称分隔的变量,因为它声明为静态的
,这就是文件范围内变量的含义
因此,每个变量都有一个单独的地址,因为变量的值是它自己的地址,所以每个变量都有一个不同的值
您可以在报头中声明变量,并在实现中定义它,以便只有一个这样的变量。标题中的声明如下所示:
extern void * const kStrokeColorWellChangedContext;
void * const kStrokeColorWellChangedContext = (void*)&kStrokeColorWellChangedContext;
其中一个实现文件中的定义如下所示:
extern void * const kStrokeColorWellChangedContext;
void * const kStrokeColorWellChangedContext = (void*)&kStrokeColorWellChangedContext;
注意,我将变量aconst
指针设为void。这不允许为它赋值,因为它应该是一个常量。您的静态void
行中似乎有一个输入错误。=
的两侧引用相同的变量名。这可能不是你想要做的。我知道这看起来很奇怪,但这似乎是Nhipster上所支持的方式-虽然在这种情况下没有显示addObserver代码,但是有或没有-,这应该是相同的-,你不能将po
与context
参数一起使用,因为context
不是对象。这就是为什么你看到一条错误消息说“这可能是给无效对象的消息…”是的,这是我的错误,我一直认为po
代表“打印输出”哈哈。感谢您的更正,我已经编辑了带有更改的问题,但是,与字符串值进行比较不是更简单,并且有助于避免这种混淆吗?我测试的范围是检查传递到-observeValue
中的上下文的值。然后在lldb
中,我键入了pokstrokecolorwellchangedcontext
。这两个值不相同,我可以确认视图正在向主控制器发送通知,因为如果我交换上下文,我将用字符串传递到-addObserver
,我可以看到context
的值是字符串,没有添加其他观察者吗?是的,实际上--我在另一个视图中有完全相同的设置,除了名为kFillColorWellChangedContext的上下文外,所有内容都是相同的。但是这个上下文值与传递到observeValue
的上下文不一样,我也可以删除它,同样的问题仍然存在。非常混乱,因为我们在工作区的其他地方使用了这种模式,而且效果很好。我会尝试删除另一个观察者。我还要检查视图是否是您期望的视图No go:\并确保视图是我期望的视图。编辑问题以包含调试结果这是正确答案-我错过了“标题”部分。很好。太棒了,谢谢你把它分解并解释——包括const
关键字。如果您有时间,可以问一个简单的问题:您提到导入标题的每个翻译单元都将创建一个单独的变量。但我记得读过这样一篇文章,即“导入”确保一个文件只包含一次。所以,如果我总是使用“导入”
,那么您知道这是如何工作的吗?每个翻译单元都导入了您的标题。它只进口我