2

概述

我在 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 处于互斥锁中。

代码和功能

我在下面重命名了变量和方法,但没有更改代码的任何其他结构。passwordRadioGroupNSMatrix*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 术语/组合并没有取得成果。

任何解决方案、故障排除建议或想法将不胜感激。如果应得的话,也欢迎为愚蠢打耳光。

4

0 回答 0