Почему мои какао-привязки сломаны? - PullRequest
0 голосов
/ 15 января 2011

У меня есть окно с NSTextField (в Snow Leopard), которое я связал с функцией NSString в моем классе WindowController. Эта строка будет объединять информацию о выборе и количестве моего табличного представления, предоставленную моим контроллером массива. Он получает начальное значение "0 0", но никогда не обновляется, когда изменяется выбор или число. Привязка выглядит следующим образом (владельцем файла является MyWindowController):

alt text

Я реализовал + (NSSet *)keyPathsForValuesAffecting<key> (ниже), но привязка никогда не обновляется, даже когда изменяется общее количество и выбор контроллера массива.

( Выполнено дополнительное устранение неполадок ) Изначально я использовал привязку Display Pattern Value для NSTextField, но мне требовалась более сложная логика, чем та, которая предоставлялась. Затем я начал прослушивать события изменения / изменения выбора в TableView, который отображает содержимое контроллера массива и динамически изменяет привязки значений шаблона отображения, но это выглядит как хак и слишком сложный.

Я уверен, что что-то мне не хватает, но я не могу сказать, что. У кого-нибудь есть какие-либо идеи? Я прочитал документацию Apple по наблюдению за значением ключа, и это все, что нужно. Я проверил, и мой keyPathsForValuesAffectingMyString вызывают, но myString вызывают только один раз. Ниже приведен мой код ( обновлено x3 ).

Обновление 1/21

Я все еще пытаюсь понять это. Когда я addObserver до self для путей ключа arrayController, уведомления запускаются, как и ожидалось, поэтому мои пути ключей и механизм наблюдения значения ключа в порядке. Когда я вызываю [self didChangeValueForKey:@"myString"]; в моем методе observeValueForKeyPath для тех же ключей, привязка все равно не обновляется, что наводит меня на мысль, что это проблема привязок, а не проблема KVO. Я собираюсь читать о механизме привязок подробнее ...

@interface MyWindowController : NSWindowController {
    IBOutlet NSArrayController *arrayController;
}

- (NSArrayController *)arrayController;
- (NSString *)myString;

@end

@implementation MyWindowController

+ (NSSet *)keyPathsForValuesAffectingMyString {
    return [NSSet setWithObjects:
            @"arrayController.arrangedObjects",
            @"arrayController.selection",
            nil];
}

- (NSArrayController *)arrayController {
    return arrayController;
}

- (NSString *)myString {
    // Just as an example; I have more complicated logic going on in my real code
    return [NSString stringWithFormat:@"%@, %@",
            [arrayController valueForKeyPath:@"arrangedObjects.@count"], 
            [arrayController valueForKeyPath:@"selection.@count"]];
}

@end

Ответы [ 5 ]

2 голосов
/ 25 марта 2011

Я подтвердил точно такую ​​же ошибку. Кто-то из Cocoabuilder догадался, почему произошла ошибка:

http://www.cocoabuilder.com/archive/cocoa/284396-why-doesn-nsarraycontroller-selection-et-al-fire-keypathsforvaluesaffectingkey.html#284400

Я не могу сказать, верно ли это объяснение, но я определенно не могу заставить + keyPathsForValues ​​... работать с NSArrayControllers.

1 голос
/ 22 января 2011

У меня есть обходной путь, но я не рад этому, так как в этом нет необходимости, и я все равно предпочел бы, чтобы привязки работали правильно. Я не приму этот ответ и удалю его, если кто-то опубликует фактическое исправление. </disclaimer>

@interface MyWindowController : NSWindowController {
    IBOutlet NSArrayController *arrayController;
    IBOutlet NSTextField *fieldThatShouldBeBinded;
}

- (NSString *)myString;

@end

@implementation MyWindowController

- (void)awakeFromNib {
    [arrayController addObserver:self
                      forKeyPath:@"selection"
                         options:0
                         context:NULL];
    [arrayController addObserver:self
                      forKeyPath:@"arrangedObjects"
                         options:0
                         context:NULL];
}

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context {
    if( object == arrayController )
        [fieldThatShouldBeBinded setStringValue:[self myString]];
}

- (NSString *)myString {
    return [NSString stringWithFormat:@"%@, %@",
            [arrayController valueForKeyPath:@"arrangedObjects.@count"], 
            [arrayController valueForKeyPath:@"selection.@count"]];
}

@end
0 голосов
/ 05 марта 2013

Я столкнулся с той же проблемой и нашел другой способ (но это все еще обходной путь). Вы должны объявить свойство динамического обхода. В разделе реализации просто верните новый пустой объект для него. Теперь вы можете KVO это обходное свойство.

@property(nonatomic,retain) NSArray *workaround;
@dynamic workaround;
- (NSArray *)workaround { return [NSArray array]; } // new *every* time
- (void)setWorkaround:(NSArray *)unused { }

+ (NSSet *)keyPathsForValuesAffectingMyString { return [NSSet setWithObject:@"workaround"]; }

Чтобы получить эту работу, вам все равно нужно вручную связать self.workaround с arrayController.selectedObjects (или любым другим):

- (void)awakeFromNib // or similar place
{
    [super awakeFromNib];
    [self bind:@"workaround" toObject:arrayController withKeyPath:@"selectedObjects" options:nil];
}

Ручное связывание работает как положено, обходной путь обновляется в соответствии с тем, к чему вы его привязали. Но KVO проверяет, действительно ли значение свойства было изменено (и прекращает распространение, если оно одинаковое). Если вы каждый раз возвращаете новое значение self.workaround, оно работает.

Предупреждение: никогда вызовите -[setWorkaround:] самостоятельно - это эффективно очистит другую сторону привязки (arrayController.selectedObjects в этом случае).

У этого метода есть некоторые преимущества: вы избегаете централизованного наблюдать за VALUEForKeyPath: ... и ваша логика находится в нужном месте. И он хорошо масштабируется, просто добавьте обходной путь2, 3 и т. Д. Для подобных случаев.

0 голосов
/ 17 января 2011

Не используйте ключевое слово @count. Привязки и KVO на контроллерах массива будут обновляться при изменении содержимого. Если это не сработает, значит, есть проблема где-то еще.

Другой вариант - использовать привязки шаблонов отображения вместо составного свойства. Привязать шаблон отображения Value1 к arrayController.arrangedObjects. @ Count и Показать шаблон Value2 к arrayController.selection. @ Count и установить шаблон в «% {value1} @,% {value2} @"

0 голосов
/ 15 января 2011

Убедитесь, что розетка arrayController подключена в Интерфейсном Разработчике. Я предполагаю, что это ноль.

...