Использование конструктора интерфейса для создания Loabable Views - PullRequest
1 голос
/ 10 мая 2011

Новый метод извлечения элементов из файлов пера.

Пример ответа ниже.

Этот новый ответ является последним изменением в этом проекте и вопрос

Я хочу создать подкласс UIView и хочу создать файл построителя интерфейса для UIView. Как бы я подключил владельца файла к себе. Я хочу иметь возможность спроектировать представление и заставить его создавать соединения, но мне не нужен контроллер представления.

Кроме загрузки пера в массив, можно ли использовать файл пера в качестве соединителя для самого представления?

Надеюсь, я правильно спрашиваю. Я уточню это.

Создание UIViewController Мне предоставляется возможность создать файл XIB для него. В это время я могу добавить UIViews в XIB, и эти подключения будут сделаны. Однако у владельца файлов, похоже, нет связанного с ним редактора пользовательского интерфейса, поэтому я хочу создать UIView, который станет вложенным представлением в другом представлении. Я действительно не хочу создавать его с помощью кода, потому что это неудобно размещать элементы вручную. Поэтому я хочу использовать ту же конструкцию для создания небольшого пользовательского интерфейса для вставки в

EDIT:

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

Я хотел найти элегантный способ загрузки UIView из пера. и с некоторой информацией от пользователя переполнения стека PeyloW мне удалось сделать именно это.

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

  • Прежде всего, я создал Xib-файл с именем «TableViewCells.xib»
    (Имя соответствует имени класса, поэтому [[self class] description] == "TableViewCells")
  • Затем я создал классы, которые я использую для представлений в Nib. Классы не имеют значения, просто убедитесь, что для объектов класса в конструкторе интерфейсов выбран «Пользовательский класс»
  • Наконец, я создал класс "TableViewCells", соответствующий имени файла xib

Мой новый заголовочный файл.
(Каждый из импортированных заголовочных файлов связан с элементами в одном xib-файле.)

#import <Foundation/Foundation.h>
#import "TitleCell.h"
#import "ToggleCell.h"
#import "ButtonCell.h"
#import "TextCell.h"

@interface TableViewCells : NSObject {
    UINib *uiNibHolder;
}

@property (nonatomic, readonly) NSArray *nibArray;

// These are the classes that will be loadable.
- (TitleCell*) titleCell;
- (ToggleCell*) toggleCell;
- (ButtonCell*) buttonCell;
- (TextCell*) textCell;
- (id) loadViewByClass: (id) viewClass;
@end

и файл класса.

loadViewByClass: метод, который находит элемент в файле пера.
вспомогательные средства доступа имеют правильный тип для объектов класса, в которые должны быть созданы экземпляры.
ПРИМЕЧАНИЕ. Я бы не рекомендовал загружать в него группу представлений. Чем больше представлений вы загрузите, тем больше будет создаваться при загрузке файла пера.

#import "TableViewCells.h"

@implementation TableViewCells

@synthesize nibArray;

- (void) unloadProperties{
    [uiNibHolder release];
}
- (NSArray *)nibArray{
    return [uiNibHolder instantiateWithOwner:nil options:nil];
}
- (id) init{
    if ((self = [super init]))
    {
        // Im using the class name for the Xib file. 
        // This means it will look in TableViewCells.xib
        // You can change the class name, or pass a Nib name to this class 
        uiNibHolder = [[UINib nibWithNibName:[[self class] description] bundle: [NSBundle mainBundle]] retain];
    }
    return self;
}
- (TitleCell *)titleCell{
    return [self loadViewByClass:[TitleCell class]];
}
- (ToggleCell *)toggleCell{
    return [self loadViewByClass:[ToggleCell class]];
}
- (ButtonCell *)buttonCell{
    return [self loadViewByClass:[ButtonCell class]];
}
- (TextCell *)textCell{
    return [self loadViewByClass:[TextCell class]];
}
- (id)loadViewByClass:(Class)viewClass{
    for (id item in self.nibArray) 
    {
        if ([item isKindOfClass:viewClass])
        {
            return item;
        }
    }
    return nil;
}

- (void)dealloc{
    [self performSelector:@selector(unloadProperties)];
    [super dealloc];
}

@end

Возможность загружать по классам невероятно приятна. И если класс отсутствует в файле xib, он вернет nil.

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

В качестве демонстрации я использовал TableView для загрузки множества представлений

@synthesize tableViewCellLoader = _tableViewCellLoader;
- (TableViewCells *)tableViewCellLoader{
    if (_tableViewCellLoader == nil){
        _tableViewCellLoader = [[TableViewCells alloc] init];
    }
    return _tableViewCellLoader;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    switch (indexPath.row) {
        case 0:
            return self.tableViewCellLoader.toggleCell;
            break;
        case 1: 
            return self.tableViewCellLoader.textCell;
            break;
        case 2:
            return self.tableViewCellLoader.titleCell;
            break;
        case 3:
            return self.tableViewCellLoader.buttonCell;
            break;
    }
    return nil;
}

Как вы можете видеть, я лениво загрузил свой TableViewCellLoader и, если бы захотел, мог бы заставить класс TableViewCells лениво загружать объекты UINib только тогда, когда их классы были вызваны.

Я люблю удобство в коде.

И все же, Еще раз спасибо PeyloW.

Ответы [ 3 ]

1 голос
/ 10 мая 2011

Владелец файлов является только прокси-объектом, его не нужно указывать во время выполнения, но он всегда будет виден во время разработки в Интерфейсном Разработчике.

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

NSArray* rootObject = [[NSBundle mainBundle] loadNibNamed:@"MyNib" 
                                                    owner:nil 
                                                  options:nil];

То, что вы передаете для аргумента owner, - это то, что передается как прокси Владелец файла при загрузкеnib, nil работает просто отлично.

Массив rootObject содержит все объекты корневого уровня, но без прокси.Обратите внимание, что массив автоматически высвобождается, поэтому, если вам нужно, чтобы загруженные объекты оставались рядом, вы должны сохранить массив или просто интересующие вас элементы.

Не то, чтобы использование loadNibNamed:owner:options: ограничивало ввод-вывод.Если требуется производительность, вам следует использовать экземпляр UINib для кэширования файла NIB в памяти и создания из него объектов.

UINib* myNib = [[UINib nibWithNibName:@"MyNib" 
                               bundle:[NSBundle mainBundle]] retain];
// And then instantiate using:
NSArray* rootObject = [myNib instantiateWithOwner:nil
                                          options:nil];
0 голосов
/ 14 мая 2013

Самый новый ответ от меня

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

Вот класс, который я использую для выполнения этой задачи.

LSObjectLoader.h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface LSObjectLoader : NSObject {
    UINib *nibHolder;
    NSString *currentNibName;
    NSArray *nibArray;
}

- (id) loadViewFromNib: (NSString*) nibName ofClassType:(Class) classType;

@end

LSObjectLoader.m

//
//  LSObjectLoader.m
//  APMobile
//
//  Created by jason.mckinley on 2/8/12.
//  Copyright (c) 2012 LoKi-Systems. All rights reserved.
//

#import "LSObjectLoader.h"

@implementation LSObjectLoader

- (id) loadViewFromNib: (NSString*) nibName ofClassType:(Class) classType
{
    if (![currentNibName isEqualToString:nibName])
    {
        currentNibName = [nibName copy];
        nibHolder = [UINib nibWithNibName:currentNibName bundle:[NSBundle mainBundle]];
    }
    nibArray = [nibHolder instantiateWithOwner:nil options:nil];

    for (id item in nibArray)
    {
        if ([item isKindOfClass:classType])
        {
            return item;
        }
    }

    return nil;
}

@end

Наконец, пара способов реализовать это.

Метод 1 Загрузка напрямую.

LSObjectLoader *oLoader = [[LSObjectLoader alloc] init];
MyClass *thisInstance = [oLoader loadViewFromNib:@"TableViewCells"
                                     ofClassType:[MyClass class]];

Метод 2 Класс загружает сам

Файл Nib "TableViewCells.xib"(Содержит объект класса «MyChatCell»)

Файл класса «MyChatCell.h / MyChatCell.m»

Заголовок

#import <UIKit/UIKit.h>

@interface MyChatCell : UITableViewCell

@property (weak, nonatomic) IBOutlet UILabel *name;
@property (weak, nonatomic) IBOutlet UILabel *message;
@property (weak, nonatomic) IBOutlet UIImageView *image;

+ (MyChatCell*) newChatCell;

@end

Реализация

#import "MyChatCell.h"
#import "LSObjectLoader.h"

@implementation MyChatCell

+ (LSObjectLoader*) nibLoader{
    static LSObjectLoader *_objectLoader;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _objectLoader = [[LSObjectLoader alloc] init];
    });
    return _objectLoader;
}


+ (MyChatCell *)newChatCell{
    return [[self nibLoader] loadViewFromNib:@"TableViewCells" ofClassType:[self class]];
}

- (id)initWithCoder:(NSCoder *)aDecoder{
    self = [super initWithCoder:aDecoder];
    if (self){
        // This is the init code for nib loading
    }
    return self;
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}

@end

Метод 3 Пользовательский класс загрузчика

Файл пера "MyChatCells.xib" (содержит объекты класса "MeChat" и "ThemChat")

Файл класса "MyChatCells.h/MyChatCells.m"

Файл заголовка

#import <UIKit/UIKit.h>
#import "MeChat.h"
#import "ThemChat.h"

@interface MyChatCells : NSObject

+ (MeChat*) newMeChat;
+ (ThemChat*) newThemChat;

@end

Файл реализации

#import "MyChatCells.h"

@implementation MyChatCells

+ (LSObjectLoader*) nibLoader{
    static LSObjectLoader *_objectLoader;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _objectLoader = [[LSObjectLoader alloc] init];
    });
    return _objectLoader;
}

+ (MeChat*)newMeChat{
    return [[self nibLoader] loadViewFromNib:NSStringFromClass([self class])
                                 ofClassType:[MeChat class]];
}

+ (ThemChat*)newThemChat{
    return [[self nibLoader] loadViewFromNib:NSStringFromClass([self class])
                                 ofClassType:[ThemChat class]];
}

@end
0 голосов
/ 10 мая 2011

Вы можете сделать это, но нет причин, по которым вы не можете создавать IBOutlets в вашем UIView и напрямую подключаться к ним. Так что в xib-файле у вас будет корневой UIView, убедитесь, что вы изменили класс на свой собственный класс. Затем вы можете установить выходы непосредственно на представление, вы не обязаны использовать владельца файла.

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