Как загрузить UIView с помощью nib-файла, созданного с помощью Interface Builder - PullRequest
237 голосов
/ 14 мая 2009

Я пытаюсь сделать что-то немного сложное, но то, что должно быть возможным. Так что это вызов для всех вас, экспертов (на этом форуме собрались многие из вас, ребята :)).

Я создаю «компонент» вопросника, который я хочу загрузить на NavigationContoller (мой QuestionManagerViewController). «Компонент» - это «пустой» UIViewController, который может загружать различные представления в зависимости от вопроса, на который необходимо ответить.

Я делаю это так:

  1. Создание объекта Question1View в качестве подкласса UIView, определяющего некоторый IBOutlets.
  2. Создайте (используя Interface Builder) Question1View.xib (ЗДЕСЬ, ГДЕ МОЯ ПРОБЛЕМА, ВОЗМОЖНО, ). Я установил UIViewController и UIView для класса Question1View.
  3. Я связываю торговые точки с компонентом вида (используя IB).
  4. Я переопределяю initWithNib моего QuestionManagerViewController, чтобы он выглядел следующим образом:

    - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
        if (self = [super initWithNibName:@"Question1View" bundle:nibBundleOrNil]) {
            // Custom initialization
        }
        return self;
    }
    

Когда я запускаю код, я получаю эту ошибку:

2009-05-14 15: 05: 37.152 iMobiDines [17148: 20b] *** Завершение работы приложения из-за необработанного исключения «NSInternalInconsistencyException», причина: «-[UIViewController _loadViewFromNibNamed:bundle:] загрузил перо« Question1View », но выход из представления не был установлен. '

Я уверен, что есть способ загрузить представление, используя nib-файл, без необходимости создавать класс viewController.

Ответы [ 24 ]

1 голос
/ 18 июня 2016

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

1) Создать класс myCustomView , унаследованный от UIView .
enter image description here

2) Создать .xib с именем myCustomView .
enter image description here

3) Измените класс UIView внутри вашего .xib файла, назначьте myCustomView Класс там.
enter image description here

4) Создать IBOutlets
enter image description here

5) Загрузить .xib в myCustomView * customView . Используйте следующий пример кода.

myCustomView * myView = [[[NSBundle mainBundle] loadNibNamed:@"myCustomView" owner:self options:nil] objectAtIndex:0];
[myView.description setText:@"description"];

Примечание: для тех, кто все еще сталкивается с проблемой, можете прокомментировать, я предоставлю им ссылку примера проекта с myCustomView

0 голосов
/ 05 января 2018

Чтобы программно загрузить представление из пера / сгиб в Swift 4:

// Load a view from a Nib given a placeholder view subclass
//      Placeholder is an instance of the view to load.  Placeholder is discarded.
//      If no name is provided, the Nib name is the same as the subclass type name
//
public func loadViewFromNib<T>(placeholder placeholderView: T, name givenNibName: String? = nil) -> T {

    let nib = loadNib(givenNibName, placeholder: placeholderView)
    return instantiateView(fromNib: nib, placeholder: placeholderView)
}

// Step 1: Returns a Nib
//
public func loadNib<T>(_ givenNibName: String? = nil, placeholder placeholderView: T) -> UINib {
    //1. Load and unarchive nib file
    let nibName = givenNibName ?? String(describing: type(of: placeholderView))

    let nib = UINib(nibName: nibName, bundle: Bundle.main)
    return nib
}

// Step 2: Instantiate a view given a nib
//
public func instantiateView<T>(fromNib nib: UINib, placeholder placeholderView: T) -> T {
    //1. Get top level objects
    let topLevelObjects = nib.instantiate(withOwner: placeholderView, options: nil)

    //2. Have at least one top level object
    guard let firstObject = topLevelObjects.first else {
        fatalError("\(#function): no top level objects in nib")
    }

    //3. Return instantiated view, placeholderView is not used
    let instantiatedView = firstObject as! T
    return instantiatedView
}
0 голосов
/ 19 марта 2013

Я закончил тем, что добавил категорию в UIView для этого:

 #import "UIViewNibLoading.h"

 @implementation UIView (UIViewNibLoading)

 + (id) loadNibNamed:(NSString *) nibName {
    return [UIView loadNibNamed:nibName fromBundle:[NSBundle mainBundle] retainingObjectWithTag:1];
 }

 + (id) loadNibNamed:(NSString *) nibName fromBundle:(NSBundle *) bundle retainingObjectWithTag:(NSUInteger) tag {
    NSArray * nib = [bundle loadNibNamed:nibName owner:nil options:nil];
    if(!nib) return nil;
    UIView * target = nil;
    for(UIView * view in nib) {
        if(view.tag == tag) {
            target = [view retain];
            break;
        }
    }
    if(target && [target respondsToSelector:@selector(viewDidLoad)]) {
        [target performSelector:@selector(viewDidLoad)];
    }
    return [target autorelease];
 }

 @end

объяснение здесь: viewcontroller меньше загрузки представления в ios & mac

0 голосов
/ 09 декабря 2013

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

Пример для класса с именем MyView.

  • Создайте файл пера MyView.xib в Интерфейсном Разработчике
  • В Интерфейсном Разработчике добавьте UIView. Установите его класс в MyView. Настройте по своему вкусу, подключите переменные экземпляра MyView к подпредставлениям, к которым вы, возможно, захотите обратиться позже.
  • В своем коде создайте новый MyView, например:

    MyView * myView = [MyView nib_viewFromNibWithOwner: owner];

Вот категория для этого:

@implementation UIView (nib)

+ (id) nib_viewFromNib {
    return [self nib_viewFromNibWithOwner:nil];
}

+ (id) nib_viewFromNibWithOwner:(id)owner {
    NSString *className = NSStringFromClass([self class]);
    NSArray *nib = [[NSBundle mainBundle] loadNibNamed:className owner:owner options:nil];
    UIView *view = nil;
    for(UIView *v in nib) {
        if ([v isKindOfClass:[self class]]) {
            view = v;
            break;
        }
    }
    assert(view != nil && "View for class not found in nib file");
    [view nib_viewDidLoad];
    return view;
}

// override this to do custom setup
-(void)nib_viewDidLoad {

}

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

...