Используя ID <protocol>для владельца файла в Интерфейсном Разработчике? - PullRequest
9 голосов
/ 21 февраля 2012

У меня есть пользовательский UITableViewCell, который я создаю из пера, используя instantiateWithOwner:(id)owner options:(NSDictionary *)options. Когда создается перо, я сохраняю его в IBOutlet, определенный в моем контроллере представления, который устанавливается как владелец файла в файле .xib. Все отлично работает.

Теперь я столкнулся с необходимостью использования этой пользовательской ячейки в нескольких контроллерах представления. Я надеялся, что смогу определить протокол (например, CustomCellOwner), который могли бы реализовать несколько контроллеров представления. Протокол просто определит IBOutlet, используемый для ссылки на ячейку при создании экземпляра.

Так что в идеале я бы хотел установить "владельца файла" на:

id <CustomCellOwner>

в Интерфейсном Разработчике.

Однако Интерфейсный Разработчик, кажется, только позволяет установить владельца файла для известного класса, а не для идентификатора, реализующего протокол?

Есть ли способ сделать это? Или более простой способ решения этой проблемы?

Спасибо!

Ответы [ 5 ]

3 голосов
/ 21 февраля 2012

Это не то решение, о котором вы просите, но вы можете создать подкласс UIViewController, который вы подклассируете для каждого контроллера представления, который должен использовать ваше перо. Что-то вроде:

@interface CustomCellOwnerViewController : UIViewController
@property (nonatomic, strong) IBOutlet UIButton *someButton;
-(IBAction)doSomething;
@end

И затем используйте это как базовый класс для каждого:

@interface FirstView : CustomCellOwnerViewController

Тогда вы можете просто установить File's Owner на CustomCellOwnerViewController без проблем.

Просто идея.

1 голос
/ 02 июня 2012

Другой вариант может заключаться в создании легкого «фабричного» объекта, который обрабатывает создание ячеек для вас.Этот объект будет FilesOwner в построителе интерфейса с соответствующим образом установленным выходом rootObject.

@interface NibLoader : NSObject

@property (nonatomic, strong) UINib     * nib;
@property (nonatomic, strong) IBOutlet id rootObject;

- (id)initWithNibName:(NSString *)name bundle:(NSBundle *)bundleOrNil;
- (id)instantiateRootObject;

@end


@implementation NibLoader

@synthesize nib, rootObject;

- (id)initWithNibName:(NSString *)name bundle:(NSBundle *)bundleOrNil {
    self = [super init];
    if (self) {
        self.nib = [UINib nibWithNibName:name bundle:bundleOrNil];
    }
    return self;
}

- (id)instantiateRootObject {
    self.rootObject = nil;
    [self.nib instantiateWithOwner:self options:nil];
    NSAssert(self.rootObject != nil, @"NibLoader: Nib did not set rootObject.");
    return self.rootObject;
}

@end

Затем в контроллерах вида:

NibLoader *customCellLoader = [[NibLoader alloc] initWithNibName:@"CustomCell" bundle:nil];
self.customCell = customCellLoader.instantiateRootObject; 

Я предпочитаю явно устанавливатькорневой объект вместо поиска в массиве, возвращенном из instantiateWithOwner:options:, потому что я знаю, что положение объектов в этом массиве изменилось в прошлом.

1 голос
/ 02 июня 2012

В iOS 5.0 теперь есть метод registerNib:forCellReuseIdentifier: на UITableView, который, я считаю, пытается решить подобную проблему.

Из документации:

Когда вы регистрируете объект пера в табличном представлении, а затем вызываете метод dequeueReusableCellWithIdentifier:, передавая зарегистрированный идентификатор, табличное представление создает ячейкуиз nib-объекта, если он еще не находится в очереди на повторное использование.

Это может быть альтернативный подход в зависимости от ваших требований.

1 голос
/ 11 апреля 2012

Создание поддельного владельца будет работать;однако такое решение может быть хрупким и нерастяжимым.В некотором смысле, клетка владеет собой, но даже это технически неверно.Правда в том, что у UITableViewCell нет владельцев.

Правильный способ реализации пользовательских ячеек табличного представления - сначала создать пользовательский подкласс UITableViewCell.В этом классе вы определите все IBOutlets и тому подобное для ячейки.Вот пример файла заголовка:

@interface RBPersonCell : UITableViewCell

@property (nonatomic, strong) IBOutlet UILabel * nameLabel;
@property (nonatomic, strong) IBOutlet UILabel * ageLabel;

- (void)setupWithPerson:(Person *)person;

@end

Оттуда у меня есть удобный метод, который при необходимости создает ячейку из пера:

+ (id)cellForTableView:(UITableView *)tableView reuseIdentifier:(NSString *)reuseID fromNib:(UINib *)nib {

    if (!reuseID)
        reuseID = [self cellIdentifier];

    id cell = [tableView dequeueReusableCellWithIdentifier:reuseID];

    if (!cell) {

        NSArray * nibObjects = [nib instantiateWithOwner:nil options:nil];

        // Sanity check. 
        NSAssert2(([nibObjects count] > 0) && 
                  [[nibObjects objectAtIndex:0] isKindOfClass:[self class]],
                  @"Nib '%@' does not appear to contain a valid %@", 
                  [self nibName], NSStringFromClass([self class]));

        cell = [nibObjects objectAtIndex:0];
    }

    return cell;
}

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

Со всем этим кодом вы готовы работать в Интерфейсном Разработчике.Сначала вам нужно установить пользовательский класс в проверке личности.Далее, не забудьте установить идентификатор вашей ячейки.Для удобства лучше использовать имя пользовательского класса.Когда вы перетаскиваете свои соединения, а не перетаскиваете их в Владелец файла, перетаскивайте свои соединения в саму пользовательскую ячейку.

Большая часть того, что я узнал о пользовательских ячейках табличного представления, получена из рецептов iOS рецептов 15-16.Вот бесплатная выписка непосредственно с Прагматическая книжная полка .Вы можете проверить эту книгу для более подробной информации.

РЕДАКТИРОВАТЬ:

Я наконец-то нашел время, чтобы открыть свой класс RBSmartTableViewCell.Вы можете найти его на моем GitHub .Вы должны найти этот класс более полезным, чем код непосредственно из рецептов iOS, поскольку мой класс обрабатывает все ячейки одинаково, независимо от того, созданы ли они с использованием XIB, UIStoryboard или кода.Этот репо также включает рабочие образцы.

1 голос
/ 04 апреля 2012

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

Сначала я создал класс "fakeOwner", подобный этому:

@interface fakeOwner : NSObject
@property (nonatomic, assign) IBOutlet MyBaseCell* itemTableCell;
@end

@implementation fakeOwner
@synthesize itemTableCell;
@end

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

    [[NSBundle mainBundle] loadNibNamed:@"MyBaseCell" owner:self options:nil];
    MyBaseCell* itemCell = self.itemTableCell;
    self.itemTableCell = nil;

Поскольку fakeOwner и мой контроллер имеют один и тот же IBOutlet, загрузка ячейки с контроллером в качестве владельца приводит к установлению соединения, даже если это не то, что явно установлено в XIB.

Не 100%, если управление памятью в настоящее время правильно (я думаю, что это нормально), но в остальном, похоже, работает отлично. Я хотел бы увидеть лучший способ сделать это, хотя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...