重要更新:我发现我的大部分问题都是基于一个错误的前提(见下面我的回答)。通知实际上到达了接收者,他们到达那里的速度太快了。(虽然,它仍然没有解释为什么有断点和没有断点的行为是不同的。)
我正在开发计算给它的文件的哈希值的应用程序。计算发生在 SHHashComputer 中。它是一个抽象类(好吧,是抽象的,因为在 Objective C 中没有抽象类),它接受文件路径并创建一个 NSInvocationOperation。反过来,它调用方法 (void)computeAndSendHash,该方法使用保存在对象中的文件路径来计算哈希并将其作为通知发送。实际计算发生在子类需要覆盖的 (NSString*)computeHash 方法中。
这是 SHHashComputer.m:
- (NSString*)computeHash {
return [NSString stringWithFormat:@"unimplemented hash for file %@", self.path];
}
- (void)computeAndSendHash {
NSString *result = [self computeHash];
NSString *notificationName = [NSString stringWithFormat:@"%@%@",
gotResultNotification,
self.hashType];
[[NSNotificationCenter defaultCenter] postNotificationName:notificationName
object:result];
self.operation = nil;
}
这是 SHMD5Computer.m(SHHashComputer 的子类):
- (NSString*)computeHash {
return @"MD5 test"; // it actually doesn't matter what it returns
}
我不会用通知的接收者来打扰你。让我们说,只要我在 SHMD5Computer.m 中注释掉 computeHash 方法,一切正常:接收到带有文本“未实现 ...”的通知并在 GUI 中显示。但如果我不这样做——那么它就会变得非常有趣。
如果我不设置任何断点,则通知永远不会到来。但是,如果我在 SHMD5Computer.h 中的 computeHash 声明处设置断点,然后单步执行,直到出现“self.operation = nil”行,并在该点继续执行,通知就会到达目的地。如果我不停在那里,调试器会突然切换到状态,就好像它没有调试任何东西一样,应用程序会冻结。
我不认为“WTF”是一个很好的问题形式,所以让我这样说:我错过了什么吗?我的代码有错误吗?什么会导致 xcode 中出现这种行为?我怎样才能解决这个问题?
(如果你想得到我所有的代码来重现它,我很乐意把它给你。)
更多实验:
如果我在断点处停止后继续执行,应用程序在接收通知的代码中遇到 EXC_BAD_ACCESS 错误,在最后一行:
id newResult = [newResultNotification object]; if (newResult == nil) [NSException raise:@"No object" format:@"Expected object with notification!"]; else if (![newResult isKindOfClass:[NSString class]]) [NSException raise:@"Not NSString" format:@"Expected NSString object!"]; else self.result = (NSString*) newResult; [self.textField setStringValue:self.result];
当我试图重现之前的实验时,发生了更奇怪的事情。在我的调试设置中,我有两个哈希计算机对象:一个 SHMD5HashComputer(我们正在讨论)和一个 SHHashComputer(当然,它产生“未执行的”哈希)。在之前的所有实验中,只要app没有崩溃,通知表单SHHashComputer总是成功到达。但在这种情况下,两个通知都没有到达,应用程序也没有崩溃。(所有步骤与前一个完全相同)。
- 正如 Josh Caswell 在评论中指出的那样,我没有正确使用通知。如文档中所述,我应该将对象本身作为通知对象发送。我解决了这个问题,我得到了完全相同的结果。(这意味着我正确地修复了它,因为有时通知可以正常工作,而且这不是问题)。
更多更新:
我发送的通知应该到达 SHHashResultViewController。这就是我创建它并注册通知的方式:
- (id)initWithHashType:(NSString *)hashType {
self = [self initWithNibName:@"SHHashResultView" bundle:[NSBundle mainBundle]];
if (self) {
[self setHashType:hashType];
}
return self;
}
- (void)setHashType:(NSString *)hashType {
[self.label setStringValue:[NSString stringWithFormat:@"%@:", hashType]];
_hashType = hashType;
NSString *notificationName = [NSString stringWithFormat:@"%@%@",
gotResultNotification,
_hashType];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(gotResult:)
name:notificationName
object:nil];
}