2010-09-30 3 views
4

Это действительно странная проблема, которую я вижу в своем приложении. У меня есть NSTextField, связанный с атрибутом объекта NSManagedObject, но всякий раз, когда объект сохраняется, текстовое поле теряет фокус. Я постоянно обновляю значение привязки, поэтому это далеко не идеально.NSManagedObjectContext save приводит к тому, что NSTextField теряет фокус

Кто-нибудь видел что-либо подобное раньше, и (надеюсь) нашел решение?

+0

Вы сохраняете контекст при каждом изменении? Потеря фокуса Textfield - это нормальное поведение при сохранении NSManagedObjectContext. Проверьте протокол NSEditor для получения дополнительной информации –

+0

Ну не на каждом изменении - он настроен на сохранение на задержку по времени и только в том случае, если контекст имеет изменения. Я не знал о протоколе NSEditor - мне придется немного переосмыслить это - спасибо! –

+0

Я использую функцию автосохранения, которая поставляется с 10.7 для моего приложения на основе NSPsistentDocument. Теперь, когда операции сохранения обрабатываются автоматически, мои текстовые поля теряют фокус всегда после ввода двух символов. Может быть, я что-то упустил, но думаю, что для этого должно быть легко. Какие-либо предложения? – Sbhklr

ответ

3

ОК, поэтому благодаря Мартину, указав, что я должен прочитать документы немного ближе. Это ожидаемое поведение, и вот что я сделал, чтобы обойти его (используйте свое мнение относительно того, подходит ли это для вас):

Я сохраняю контекст один раз каждые 3 секунды, проверяя в начале, если контекст имеет какие-либо изменения, прежде чем я начну выполнять фактический метод save: на моем NSManagedObjectContext. Я добавил простой увеличение/уменьшение NSUInteger (_saveDisabler) мой класс контроллера Core Data, который модифицирован с помощью следующих методов:

- (void)enableSaves { 
    if (_saveDisabler > 0) { 
     _saveDisabler -= 1; 
    } 
} 

- (void)disableSaves { 
    _saveDisabler += 1; 
} 

Тогда я все в моем методе пользовательских saveContext это сделать простую проверку на вершине:

if (([moc hasChanges] == NO) || (_saveDisabler > 0)) { 
    return YES; 
} 

Это предотвращает сохранение возникновения, и означает, что фокус не украдена из любой из моих пользовательских TextField подклассов. Для полноты картины, я также подклассы NSTextField и включить/отключить сохранение в моем контроллере Основных данных из следующих методов:

- (void)textDidBeginEditing:(NSNotification *)notification; 
- (void)textDidEndEditing:(NSNotification *)notification; 

Это может быть немного грязным, но это работает для меня. Я очень хочу услышать о более чистых/менее запутанных методах, если кто-то сделал это успешно по-другому.

+0

Недостатком этого является то, что если пользователь привык оставлять курсор в текстовом поле, вы никогда не сохраните его. Обычно я использую все мои текстовые поля/tokefields/etc. привязки, установленные для постоянного обновления, а затем что-то похожее на @cocoafan для восстановления firstResponder и выбора. –

5

Недавно я столкнулся с проблемой и исправил ее, изменив способ привязки NSTextField к атрибуту NSManagedObject. Вместо привязки значения текстового поля к выбору. [Attribute] путь ключа NSArrayController, я связал arrayController.selection. [Attribute] keyPath контроллера представления, у которого был правильный выход, указывающий на контроллер.

По какой-то причине NSTextField не потеряет фокус, когда NSManagedObjectContext сохраняется, если он связан таким образом.

+1

Он также исправляет мою проблему. Я использовал эти трюки для развязки привязок уже в прошлом. Интересно, может ли кто-нибудь увидеть настоящую проблему здесь. Мне кажется, что это должно быть хорошо (очевидно, если только один фрагмент пользовательского интерфейса может изменить атрибут Core Data TextField)! –

+1

Удивительно, это работает! Но почему? –

+0

Как вы это сделаете, когда текстовое поле находится внутри ячейки текстового поля в виде таблицы? – Sbhklr

4

Я хочу поделиться своим решением. Он будет работать для всех полей без изменений. Я оптимизировал его для этой публикации и удалил некоторые проверки ошибок, протоколирование и безопасность потоков.

- (BOOL)saveChanges:(NSError **)outError { 
    BOOL result = YES; 
    @try { 
    NSError *error = nil; 
    if ([self hasChanges]) { 

    // Get field editor 
    NSResponder *responder = [[NSApp keyWindow] firstResponder]; 
    NSText *editor = [[NSApp keyWindow] fieldEditor: NO forObject: nil]; 
    id editingObject = [editor delegate]; 
    BOOL isEditing = (responder == editor); 
    NSRange range; 
    NSInteger editedRow, editedColumn; 

    // End editing to commit the last changes 
    if (isEditing) { 

    // Special case for tables 
    if ([editingObject isKindOfClass: [NSTableView class]]) { 
     editedRow = [editingObject editedRow]; 
     editedColumn = [editingObject editedColumn]; 
    } 

    range = [editor selectedRange]; 
    [[NSApp keyWindow] endEditingFor: nil]; 
    } 

    // The actual save operation 
    if (![self save: &error]) { 
    if (outError != nil) 
     *outError = error; 
     result = NO; 
    } else { 
     result = YES; 
    } 

    // Now restore the field editor, if any. 
    if (isEditing) { 
     [[NSApp keyWindow] makeFirstResponder: editingObject]; 
     if ([editingObject isKindOfClass: [NSTableView class]]) 
     [editingObject editColumn: editedColumn row: editedRow withEvent: nil select: NO]; 
     [editor setSelectedRange: range]; 
     } 
    } 
    } @catch (id exception) { 
    result = NO; 
    } 
    return result; 
} 
+0

За исключением, конечно, точки редактирования не могут быть в конце (или может быть даже выбор). Просто захватите [editor selectedRange] NSRange до окончания редактирования, затем [editor SetSelectedRange:], используя сохраненный NSRange. –

+0

Вы правы. Я уже улучшил код и добавил поддержку NSTableView. Теперь я отредактировал свой ответ, чтобы поделиться им с вами. Обратите внимание, что это лишенная версии моего фактического кода, которая также включает в себя безопасность потоков и обработку ошибок. – cocoafan

Смежные вопросы