2

概要

Xcode 4.3.2 を使用して開発し、Mac OS X 10.7.5 (Mac OS X 10.6 をターゲット) でテストしている Mac OS X Cocoa アプリで奇妙な問題が発生しています。メインNIBには、メインコントローラーに1つのアウトレットと1つのアクションがありますが、他の2つの方法でも使用されます(メインコントローラーでも使用されます)。このアクションは、選択されたタグを NSUserDefaults に保存し、選択されているものに基づいて NSTextField を有効/無効にします。以下サンプル)。

基本的なことですが、ある場合 (GUI のラジオ ボタンをクリックするのではなく、プログラムで NSMatrix のセルを選択した場合)、アプリはミューテックス ロックで PWOD します。

コードと機能

以下の変数とメソッドの名前を変更しましたが、コードの他の構造は変更していません。passwordRadioGroupIBアウトレットですNSMatrix*

- (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。デバッガーでメモリ アドレスを確認し、ivar を調べることができます)。これにより、タグが正常に呼び出さ[[passwordRadioGroup selectedCell] tag]れ、NSUserDefaults に保存されます。

上記の 2 つは問題なく何度でも実行できます。終了して再起動すると、ラジオボタンが最後に残った状態に正しく復元されるため、選択したタグを確実に正しく取得し、NSUser のデフォルトに保存し、NSUserDefaults から取得し、NSMatrix のタグで選択したセルを設定します。

ここが厄介なところです:

クリックすると、他の多くの作業を実行し、最終的generateUserPasswordにそれ自体にメッセージを送信してパスワードを生成する別のボタンがあります (これもすべてメイン コントローラーで実行され、メイン スレッドで実行されます)。それが最初に行うことは何ですか?呼び出します[[passwordRadioGroup selectedCell] tag]。上に示したように、好きなだけ安全に行うことができますよね?

ラジオ ボタンの 1 つを選択すると、選択したセルが GUI を介して変更され、selectPasswordType:メッセージがメイン コントローラーに再度送信されます。問題は発生しません (ただし、少し遅く、PWOD のように見えることは認めます)。

起動後に NSMatrix をクリックしない場合(つまり、GUI から再度選択/アクションを強制しない場合)、その[[passwordRadioGroup selectedCell] tag]呼び出しgenerateUserPasswordはすぐに PWOD になります。Xcode のデバッガーで一時停止ボタンを押して現在の場所を確認すると、常にメイン スレッドでpsych_mutexwait(から呼び出されて) います。プログラムで呼び出されず、問題なく実行できたclass_lookupMethodAndLoadCache場合、少なくともある程度の正気は残っていたでしょう。selectPasswordType:[[passwordRadioGroup selectedCell] tag]

ヘルプ!

繰り返しますが、デバッガーでこれを実行したところ、メモリ アドレスと ivarpasswordRadioGroupが変更されておらず、割り当てが解除されていないことを確認できます (「ゾンビ オブジェクト」を有効にして & なしで試しました)。passwordRadioGroup私のメインコントローラーでの唯一の参照は、上記のものです。あらゆる種類の NSMatrix/radio/ selectCellWithTag/ selectedCell/ selectedTag/ class_lookupMethodAndLoadCache/mutex 用語 / 組み合わせのグーグル検索は実りがありませんでした。

解決策、トラブルシューティングの提案、または考えをいただければ幸いです。当然のことながら、愚かさへの平手打ちも歓迎します。

4

0 に答える 0