Установка NSMatrix выбора программно вызывает блокировку мьютекса при попытке позже получить выбранную ячейку
обзор
Я вижу странную проблему в приложении Mac OS X Cocoa, которое я разрабатываю с Xcode 4.3.2 и тестирую на Mac OS X 10.7.5 (для Mac OS X 10.6): у меня есть базовая радиогруппа NSMatrix основной NIB, который имеет один выход и одно действие в моем главном контроллере, но также используется в двух других методах (также в главном контроллере). Действие сохраняет выбранный тег в NSUserDefaults и включает / отключает NSTextField, на основе которого выбран, один метод является загрузчиком настроек и поэтому выбирает ячейку по тегу при загрузке, а другой метод ищет выбранный тег для другой логики (код Образцы ниже).
Базовые вещи, но в одном случае (когда программно выбирается только ячейка в NSMatrix, а не с помощью переключателя в графическом интерфейсе), приложение блокирует блокировку мьютекса.
Код и функциональность
Я переименовал переменные и методы ниже, но не изменил ни одну другую структуру кода. 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:]
, Это работает правильно, и правильный переключатель выбран в графическом интерфейсе. Наконец звонит [self selectPasswordType:passwordRadioGroup
(который также успешно вызывает [[passwordRadioGroup selectedCell] tag]
) и соответственно включает / отключает текстовое поле и записывает тег обратно в NSUserDefaults (обычно, но не всегда избыточно).
Вы можете выбрать любую из переключателей, которая отправляет selectPasswordType:
сообщение на мой главный контроллер (передавая его экземпляр passwordRadioGroup
; Я проверил адрес памяти в отладчике и могу проверить его ивары). Это успешно звонки [[passwordRadioGroup selectedCell] tag]
и сохраняет тег в NSUserDefaults.
Вы можете сделать это два раза столько раз, сколько хотите, без проблем. Выход и повторный запуск корректно восстанавливают переключатели в состояние, в котором вы оставили их последними, поэтому он определенно правильно получает выбранный тег, сохраняет его по умолчанию в NSUser, извлекает его из NSUserDefaults и устанавливает выбранную ячейку по тегу в NSMatrix.
Вот где это становится ввернутым:
Есть еще одна кнопка, которая при нажатии выполняет кучу другой работы и, в конечном итоге, отправляет generateUserPassword
сообщение самому себе для создания пароля (опять же, это все в главном контроллере и работает в главном потоке). Каково первое, что он делает? Вызовы [[passwordRadioGroup selectedCell] tag]
, Хорошо, вы можете безопасно делать это столько, сколько хотите, как показано выше, верно?
Если вы выберете одну из переключателей, то измените выбранную ячейку через графический интерфейс и отправьте selectPasswordType:
сообщение для моего главного контроллера снова, да. Вы не столкнетесь с проблемами (хотя, я признаю, это кажется немного медленным и PWOD на секунду).
Если вы не нажмете на NSMatrix после запуска (чтобы не вызывать выбор / действие снова из GUI), это [[passwordRadioGroup selectedCell] tag]
вызывать generateUserPassword
будет сразу PWOD. Если я нажимаю кнопку паузы в отладчике XCode, чтобы увидеть, где он находится, он всегда находится в psych_mutexwait
(вызывается из class_lookupMethodAndLoadCache
) в основной теме. Если selectPasswordType:
не были вызваны программно и не могут работать [[passwordRadioGroup selectedCell] tag]
без проблем я бы хоть немного здравомыслия оставил.
Помогите!
Повторюсь, я проследил это в отладчике и могу убедиться, что адрес памяти и ivars подтверждают, что passwordRadioGroup
не меняется из-под меня и не освобождается (я пробовал с & без "Zombie Objects"). Единственные ссылки на passwordRadioGroup
в моем главном контроллере те, которые видели выше. Поиск в Google для всех видов NSMatrix/ радио /selectCellWithTag
/selectedCell
/selectedTag
/class_lookupMethodAndLoadCache
/ мьютекс термины / комбинации не был плодотворным.
Любые решения, предложения по устранению неполадок или мысли будут с благодарностью. Пощечины за глупость тоже приветствуются, если заслужили.