概述
我在 Mac OS X Cocoa 应用程序中看到一个奇怪的问题,我正在使用 Xcode 4.3.2 开发并在 Mac OS X 10.7.5(针对 Mac OS X 10.6)上进行测试:我有一个基本的 NSMatrix 无线电组主 NIB 在我的主控制器中具有一个出口和一个动作,但也用于其他两种方法(也在主控制器中)。该操作将选定的标签保存到 NSUserDefaults 并启用/禁用一个 NSTextField 基于它被选中,一种方法是首选项加载器,因此在加载时按标签选择一个单元格,另一种方法查找它为其他逻辑选择的标签(代码下面的示例)。
基本的东西,但在一种情况下(仅以编程方式选择 NSMatrix 中的单元格,而不是通过单击 GUI 中的单选按钮),应用程序 PWOD 处于互斥锁中。
代码和功能
我在下面重命名了变量和方法,但没有更改代码的任何其他结构。passwordRadioGroup
是NSMatrix*
IBOutlet。
- (void)applicationDidFinishLaunching:(NSNotification*)aNotification {
// get logging up and running
[self initLogging];
// load various prefs
// ...
[self loadPasswordSettings];
}
- (void)loadPasswordSettings {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
// load password settings from our prefs
NSNumber *passwordTypeTag = [defaults objectForKey:kPasswordTypeDefaultKey];
if ( passwordTypeTag != nil ) {
[passwordRadioGroup selectCellWithTag:[passwordTypeTag intValue]];
} else {
[passwordRadioGroup selectCellWithTag:kPasswordTypeRadioRandomTag];
}
[self selectPasswordType:passwordRadioGroup];
// ...
}
- (IBAction)selectPasswordType:(NSMatrix *)sender {
NSInteger tag = [[sender selectedCell] tag];
switch ( tag ) {
case kPasswordTypeRadioRandomTag:
// disable the password text field
[passwordField setEnabled:NO];
break;
case kPasswordTypeRadioManualTag:
// enable the password text field
[passwordField setEnabled:YES];
break;
}
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithInt:tag] forKey:kPasswordTypeDefaultKey];
}
- (NSString *)generateUserPassword {
NSString *password;
// which type of password should we be generating (random or from a specifed one)?
NSInteger tag = [[passwordRadioGroup selectedCell] tag];
switch ( tag ) {
// manual password
case kPasswordTypeRadioManualTag:
password = [passwordField stringValue];
break;
// random password
case kPasswordTypeRadioRandomTag:
// password = randomly generated password;
break;
}
return password;
}
当应用程序启动时,我的主控制器会收到一条applicationDidFinishLaunching
消息,然后将 loadPasswordSettings
消息发送给它自己。loadPasswordSettings
然后发送[[passwordRadioGroup selectedCell] tag]
和发送[passwordRadioGroup selectCellWithTag:]
。这可以正常工作,并且在 GUI 中选择了正确的单选按钮。它最终调用[self selectPasswordType:passwordRadioGroup
(它也成功调用[[passwordRadioGroup selectedCell] tag]
)并适当地启用/禁用文本字段并将标签写回 NSUserDefaults(通常,但并不总是多余的)。
您可以选择任何单选按钮,它会向selectPasswordType:
我的主控制器发送一条消息(将其传递给我的实例passwordRadioGroup
;我已经在调试器中验证了内存地址并可以检查它的 ivars)。这成功调用[[passwordRadioGroup selectedCell] tag]
并将标签保存到 NSUserDefaults。
您可以根据需要多次执行上述两项操作,而不会出现问题。退出和重新启动正确地将单选按钮恢复到您上次离开的状态,因此它绝对正确地获取选定的标签,将其存储在 NSUser 默认值中,从 NSUserDefaults 中检索它,并在 NSMatrix 上按标签设置选定的单元格。
这就是它变得古怪的地方:
还有另一个按钮,当单击它时,它会执行一系列其他工作,然后最终将generateUserPassword
消息发送给自身以生成密码(同样,这一切都在主控制器中并在主线程中运行)。它做的第一件事是什么?来电[[passwordRadioGroup selectedCell] tag]
。好吧,您可以安全地随心所欲地执行此操作,如上图所示,对吧?
如果您选择其中一个单选按钮,因此通过 GUI 更改所选单元格并将selectPasswordType:
消息再次发送到我的主控制器,是的。你不会遇到任何问题(虽然,我承认它看起来有点慢,而且 PWODs 一秒钟)。
如果您在启动后未单击 NSMatrix(因此不会再次从 GUI 强制选择/操作),则该[[passwordRadioGroup selectedCell] tag]
调用generateUserPassword
将立即 PWOD。如果我在 Xcode 的调试器中点击暂停按钮来查看它的位置,它总是在主线程中psych_mutexwait
(从 调用)。class_lookupMethodAndLoadCache
如果selectPasswordType:
没有以编程方式调用并且能够[[passwordRadioGroup selectedCell] tag]
毫无问题地运行,我至少会剩下一些理智。
帮助!
重申一下,我已经在调试器中完成了这一点,并且可以验证内存地址和 ivars 确认passwordRadioGroup
没有从我下面被更改,也没有被释放(我已经尝试了 & 没有启用“僵尸对象” )。我的主控制器中唯一的引用passwordRadioGroup
是上面看到的那些。谷歌搜索各种 NSMatrix/radio/ selectCellWithTag
/ selectedCell
/ selectedTag
/ class_lookupMethodAndLoadCache
/mutex 术语/组合并没有取得成果。
任何解决方案、故障排除建议或想法将不胜感激。如果应得的话,也欢迎为愚蠢打耳光。