4

Я изо всех сил пытаюсь выполнить то, что, по моему мнению, будет относительно общей задачей. У меня есть NSTableView, который привязан к его массиву через NSArrayController. Контроллер массива имеет свой контент, установленный в NSMutableArray, который содержит один или несколько экземпляров класса модели. То, что я не знаю, как сделать, - это подвергнуть модель внутри подкласса NSCell способом, который является дружественным для привязки.Отображение объекта модели с использованием привязок в пользовательском NSCell из NSTableView

В целях иллюстрации мы будем говорить, что объектная модель - это человек, состоящий из имени, фамилии, возраста и пола. Таким образом, модель появится что-то вроде этого:

@interface PersonModel : NSObject { 
    NSString * firstName; 
    NSString * lastName; 
    NSString * gender; 
    int * age; 
} 

Очевидно соответствующие сеттеров, добытчиками инициализации и т.д. для класса.

В моем классе контроллера я определю NSTableView, NSMutableArray и NSArrayController:

@interface ControllerClass : NSObject { 
    IBOutlet NSTableView * myTableView; 
    NSMutableArray * myPersonArray; 
    IBOutlet NSArrayController * myPersonArrayController; 
} 

Используя Interface Builder можно легко связать модель с соответствующими столбцами:

myPersonArray --> myPersonArrayController --> table column binding

это работает хорошо. Поэтому я удаляю дополнительные столбцы, оставляя один скрытый столбец, связанный с NSArrayController (это создает и сохраняет связь между каждой строкой и NSArrayController), так что я попал в один видимый столбец в моем NSTableView и один скрытый столбец. Я создаю подкласс NSCell и поместите соответствующий метод рисования для создания ячейки. В моей awakeFromNib я установить пользовательские NSCell подкласса:

MyCustomCell * aCustomCell = [[[MyCustomCell alloc] init] autorelease]; 
[[myTableView tableColumnWithIdentifier:@"customCellColumn"] 
    setDataCell:aCustomCell]; 

Это тоже работает нормально с точки зрения рисования. Я получаю свою пользовательскую ячейку, отображаемую в столбце, и она повторяется для каждого управляемого объекта в контроллере массива. Если я добавлю объект или удалю объект из контроллера массива, таблица обновится соответствующим образом.

Однако ... у меня создалось впечатление, что мой объект PersonModel будет доступен из моего подкласса NSCell. Но я не знаю, как добраться до него. Я не хочу устанавливать каждый NSCell с помощью сеттеров и геттеров, потому что тогда я нарушаю концепцию всей модели, сохраняя данные в NSCell вместо ссылки на нее с контроллера массива.

И да, мне нужно иметь пользовательский NSCell, поэтому наличие нескольких столбцов не является вариантом. Куда отсюда?

В дополнение к поиску Google и StackOverflow я выполнил обязательную проверку документов Apple и, похоже, не нашел ответа. Я нашел много ссылок, которые били вокруг куста, но ничего не связано с NSArrayController. Контроллер облегчает жизнь при привязке к другим элементам модельного объекта (например, сценарий «мастер/детализация»). Я также нашел много ссылок (хотя ответов нет) при использовании Core Data, но Im не использовал Core Data.

В соответствии с нормой, я очень благодарен за любую помощь, которая может быть предложена!

ответ

3

Наконец-то выдумал это. Человек, который занимался некоторыми делами. Итак, вот что мне нужно было сделать ...

Прежде всего мне нужно было создать массив значений моей модели в моем объекте модели и вернуть эти значения ключей в NSDictionary из модели.

Таким образом, моя модель получила два новых метода следующим образом (на основе моего упрощенном примере выше):

+(NSArray *)personKeys 
{ 
    static NSArray * personKeys = nil; 
    if (personKeys == nil) 
     personKeys = [[NSArray alloc] initWithObjects:@"firstName", @"lastName", @"gender", @"age", nil]; 

    return personKeys; 
} 

-(NSDictionary *)personDictionary 
{ 
    return [self dictionaryWithValuesForKeys:[[self class] personKeys]]; 
} 

После внедрения Поручаю моей границы value в моей таблице

arrayController --> arrangeObjects --> personDictionary.

Последний шаг для ссылки на объект в NSCelldrawWithFrame и использовать по мере необходимости следующим образом:

NSDictionary * thisCellObject = [self objectValue]; 

NSString * objectFirstName = [thisCellObject valueForkey:@"firstName"]; 
NSString * objectLastName = [thisCellObject valueForKey:@"lastName"]; 

И, как я надеялся, любое изменение в модели объекта отражается в обычае NSCell.

+0

Это великолепно. Я некоторое время боролся с монстром реализации, и у него был только уродливый Франкенштейн. Хотя я использую объекты CoreData, я думаю, что это изящное решение. –

+0

@Greg - рад, что я могу быть полезным! У меня была голова, обернутая вокруг этой проблемы за несколько дней до того, как я решил решение! – Hooligancat

0

Я очень благодарен за этот пост, Хулиганкат, потому что мой проект был остановлен по этой проблеме и так же трудно, как я посмотрел на то же решение Тима Истеда на http://www.timisted.net/blog/archive/custom-cells-and-core-data/ Я не мог понять это.

Это было только тогда, когда я прочитал ваше превосходное упрощение проблемы и вашу версию решения, которое пенни упало - я очень благодарен!

+1

рад, что я мог бы помочь. Мне жаль, что я не видел эту нить, которую вы нашли !! Вероятно, спас бы мне часы! Я не использую Core Data в своих приложениях, потому что данные хранятся на стороне сервера, поэтому я склоняюсь к большим стенам, чем те, которые используют Core Data. В любом случае, у нас обоих есть рабочие решения! Kewl ... – Hooligancat

1

Существует еще один подход, который не требует словаря. Однако для этого требуется реализация метода зоны (ID) copyWithZone: (NSZone *) в вашем классе данных. Например:

- (id)copyWithZone:(NSZone *)zone { 
    Activity *copy = [[self class] allocWithZone: zone]; 
    copy.activityDate = self.activityDate; 
    copy.sport = self.sport; 
    copy.sportIcon = self.sportIcon; 
    copy.laps = self.laps; 
    return copy; } 

Сейчас в IB, вы указываете значение в столбце таблицы по адресу массива Controller -> arrangedObjects

Метод drawWithFrame теперь будет возвращать ваш фактический объект из objectValue.

Activity *rowActivity = [self objectValue]; 

Изменение класса требует обновления метода copyWithZone, а затем доступ к данным непосредственно в методе drawWithFrame.