Как загрузить UIView с помощью файла nib, созданного с помощью Interface Builder

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

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

Как я это делаю:

  • Создайте объект Question1View как подкласс UIView, определив некоторые IBOutlets.
  • Создайте (используя Interface Builder) Question1View.xib (ЗДЕСЬ, ЧТО МОЯ ПРОБЛЕМА ВЕРОЯТНА). Я установил как UIViewController, так и UIView для класса Question1View.
  • Я связываю выходы с компонентом вида (используя IB).
  • Я переопределяю 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.

Ответ 1

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

1) Создайте пользовательский вид подкласса с любыми выходами, к которым вы хотите получить доступ позже. --MyView

2) в UIViewController, который вы хотите загрузить и обработать nib, создайте свойство IBOutlet, которое будет удерживать загруженное представление nib, например

в MyViewController (подкласс UIViewController)

  @property (nonatomic, retain) IBOutlet UIView *myViewFromNib;

(не забудьте его синтезировать и выпустить в файл .m)

3) откройте свой nib (мы будем называть его "myViewNib.xib" ) в IB, установите для владельца файла значение MyViewController

4) теперь подключите свой файл "Выход пользователя myViewFromNib" к основному виду в наконечнике.

5) Теперь в MyViewController напишите следующую строку:

[[NSBundle mainBundle] loadNibNamed:@"myViewNib" owner:self options:nil];

Теперь, как только вы это сделаете, вызов вашей собственности "self.myViewFromNib" даст вам доступ к представлению из вашего nib!

Ответ 2

Спасибо всем. Я нашел способ сделать то, что хотел.

  • Создайте UIView с помощью IBOutlet, который вам нужен.
  • Создайте xib в IB, создайте его по своему вкусу и соедините его так: владелец файла имеет класс UIViewController (Нет настраиваемого подкласса, но "реальный" ). Представление "Файл владельца" подключается к основному виду, а его класс объявляется как один из шага 1).
  • Подключите элементы управления с помощью IBOutlet s.
  • DynamicViewController может запустить свою логику, чтобы решить, какой вид /xib загрузить. Как только он сделал деление, в методе loadView поставьте что-то вроде этого:

    NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:@"QPickOneView"
                                                      owner:self
                                                    options:nil];
    
    QPickOneView* myView = [ nibViews objectAtIndex: 1];
    
    myView.question = question;
    

Что это!

Основной метод bundle loadNibNamed позаботится об инициализации представления и создании соединений.

Теперь ViewController может отображать представление или другое в зависимости от данных в памяти, а "родительский" экран не должен беспокоить эту логику.

Ответ 3

Я не уверен, о чем говорят некоторые из ответов, но мне нужно поставить этот ответ здесь, когда я буду искать в Google в следующий раз. Ключевые слова: "Как загрузить UIView из ниба" или "Как загрузить UIView из NSBundle".

Здесь код почти на 100% прямо вверх от книги Apress Beginning iPhone 3 (стр. 247, "Использование новой ячейки для просмотра таблицы" ):

- (void)viewDidLoad {
    [super viewDidLoad];
    NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:@"Blah"
                                                 owner:self options:nil];
    Blah *blah;
    for (id object in bundle) {
        if ([object isKindOfClass:[Blah class]]) {
            blah = (Blah *)object;
            break;
        }
    }   
    assert(blah != nil && "blah can't be nil");
    [self.view addSubview: blah];
} 

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


Категория: NSObject + LoadFromNib

#import "NSObject+LoadFromNib.h"

@implementation NSObject (LoadFromNib)

+ (id)loadFromNib:(NSString *)name classToLoad:(Class)classToLoad {
    NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:name owner:self options:nil];
    for (id object in bundle) {
        if ([object isKindOfClass:classToLoad]) {
            return object;
        }
    }
    return nil;
}

@end

Быстрое расширение

extension UIView {
    class func loadFromNib<T>(withName nibName: String) -> T? {
        let nib  = UINib.init(nibName: nibName, bundle: nil)
        let nibObjects = nib.instantiate(withOwner: nil, options: nil)
        for object in nibObjects {
            if let result = object as? T {
                return result
            }
        }
        return nil
    }
}

И пример использования:

class SomeView: UIView {
    class func loadFromNib() -> SomeView? {
        return self.loadFromNib(withName: "SomeView")
    }
}

Ответ 4

Для всех тех, кому необходимо управлять более чем одним экземпляром настраиваемого представления, то есть Outlet Collection, я объединил и настроил ответы @Gonso, @AVeryDev и @Olie таким образом:

  • Создайте пользовательский MyView : UIView и установите его как Пользовательский класс "корня UIView в желаемом XIB; custom class

  • Создайте все выходы, которые вам нужны в MyView (сделайте это сейчас, потому что после пункта 3 IB предложит вам подключить розетки к UIViewController, а не к настраиваемому представлению как мы хотим); custom class outlet

  • Установите UIViewController как " Владелец файла" пользовательского представления XIB; enter image description here

  • В UIViewController добавьте новый UIViews для каждого экземпляра MyView, который вы хотите, и подключите их к UIViewController, создав Outlet Collection: эти представления будут действовать как "обертки" для пользовательских экземпляров просмотров; enter image description here

  • Наконец, в viewDidLoad вашего UIViewController добавьте следующие строки:

NSArray *bundleObjects;
MyView *currView;
NSMutableArray *myViews = [NSMutableArray arrayWithCapacity:myWrapperViews.count];
for (UIView *currWrapperView in myWrapperViews) {
    bundleObjects = [[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self options:nil];
    for (id object in bundleObjects) {
        if ([object isKindOfClass:[MyView class]]){
            currView = (MyView *)object;
            break;
        }
    }

    [currView.myLabel setText:@"myText"];
    [currView.myButton setTitle:@"myTitle" forState:UIControlStateNormal];
    //...

    [currWrapperView addSubview:currView];
    [myViews addObject:currView];
}
//self.myViews = myViews; if need to access them later..

Ответ 5

Я бы использовал UINib для создания экземпляра пользовательского UIView для повторного использования

UINib *customNib = [UINib nibWithNibName:@"MyCustomView" bundle:nil];
MyCustomViewClass *customView = [[customNib instantiateWithOwner:self options:nil] objectAtIndex:0];
[self.view addSubview:customView];

В этом случае необходимы файлы MyCustomView.xib, MyCustomViewClass.h и MyCustomViewClass.m. Обратите внимание, что [UINib instantiateWithOwner] возвращает массив, поэтому вы должны использовать элемент, который отражает UIView, который вы хотите повторно использовать. В этом случае это первый элемент.

Ответ 6

Не следует устанавливать класс вашего контроллера представлений как подкласс UIView в Interface Builder. Это определенно, по крайней мере, часть вашей проблемы. Оставьте это как UIViewController, некоторый подкласс этого или какой-либо другой пользовательский класс, который у вас есть.

Что касается загрузки только представления из xib, я был в предположении, что у вас должен быть какой-то контроллер вида (даже если он не расширяет UIViewController, который может быть слишком тяжелым для ваших нужд) как владелец файла в Interface Builder, если вы хотите использовать его для определения вашего интерфейса. Я сделал небольшое исследование, чтобы подтвердить это. Это связано с тем, что в противном случае не было бы никакого способа получить доступ к каким-либо элементам интерфейса в UIView, и не было бы способа запуска ваших собственных методов в коде событиями.

Если вы используете UIViewController в качестве владельца файла для своих просмотров, вы можете просто использовать initWithNibName:bundle: для его загрузки и вернуть объект контроллера вида. В IB убедитесь, что вы устанавливаете выход view в представление с вашим интерфейсом в xib. Если вы используете какой-либо другой тип объекта в качестве владельца файла, вам нужно будет использовать метод NSBundle loadNibNamed:owner:options: для загрузки nib, передав экземпляр File Owner в этот метод. Все его свойства будут установлены надлежащим образом в соответствии с выводами, которые вы определяете в IB.

Ответ 7

Вы также можете использовать UIViewController initWithNibName вместо loadNibNamed. Это проще, я нахожу.

UIViewController *aViewController = [[UIViewController alloc] initWithNibName:@"MySubView" bundle:nil];
[self.subview addSubview:aViewController.view];
[aViewController release];  // release the VC

Теперь вам просто нужно создать MySubView.xib и MySubView.h/m. В MySubView.xib задайте класс File Owner для UIViewController и просмотрите класс в MySubView.

Вы можете расположить и размер subview с помощью родительского xib файла.

Ответ 8

Это отличный вопрос (+1), и ответы были почти полезны;) Извините, ребята, но у меня было чертовски время, пробивающее это, хотя и Gonso, и AVeryDev дали хорошие подсказки. Надеюсь, этот ответ поможет другим.

MyVC - это контроллер вида, содержащий все это.

MySubview - это представление, которое мы хотим загрузить из xib

  • В MyVC.xib создайте представление типа MySubview, которое является правильным размером и формой и расположено там, где вы хотите.
  • В MyVC.h,

    IBOutlet MySubview *mySubView
    // ...
    @property (nonatomic, retain) MySubview *mySubview;
    
  • В MyVC.m, @synthesize mySubView; и не забудьте выпустить его в dealloc.

  • В MySubview.h у вас есть выход/свойство для UIView *view (может быть ненужным, но работал у меня.) Синтезируйте и отпустите его в .m
  • В MySubview.xib
    • установите тип владельца файла на MySubview и привяжите свойство вида к вашему представлению.
    • Разложите все биты и подключитесь к IBOutlet по желанию
  • Назад в MyVC.m,

    NSArray *xibviews = [[NSBundle mainBundle] loadNibNamed: @"MySubview" owner: mySubview options: NULL];
    MySubview *msView = [xibviews objectAtIndex: 0];
    msView.frame = mySubview.frame;
    UIView *oldView = mySubview;
    // Too simple: [self.view insertSubview: msView aboveSubview: mySubview];
    [[mySubview superview] insertSubview: msView aboveSubview: mySubview]; // allows nesting
    self.mySubview = msView;
    [oldCBView removeFromSuperview];
    

Сложный бит для меня был: подсказки в других ответах загрузили мой взгляд из xib, но НЕ заменили представление в MyVC (duh!) - мне пришлось поменять это самостоятельно.

Кроме того, чтобы получить доступ к методам MySubview, свойство view в файле .xib должно быть установлено на MySubview. В противном случае он возвращается как обычный UIView.

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

Ответ 9

Это то, что должно быть проще. Я закончил расширение UIViewController и добавил селектор loadNib:inPlaceholder:. Теперь я могу сказать

self.mySubview = (MyView *)[self loadNib:@"MyView" inPlaceholder:mySubview];

Здесь код для категории (он делает тот же самый rigamarole, как описано Гонсо):

@interface UIViewController (nibSubviews)

- (UIView *)viewFromNib:(NSString *)nibName;
- (UIView *)loadNib:(NSString *)nibName inPlaceholder:(UIView *)placeholder;

@end

@implementation UIViewController (nibSubviews)

- (UIView *)viewFromNib:(NSString *)nibName
{
  NSArray *xib = [[NSBundle mainBundle] loadNibNamed:nibName owner:self options:nil]; 
  for (id view in xib) { // have to iterate; index varies
    if ([view isKindOfClass:[UIView class]]) return view;
  }
  return nil;
}

- (UIView *)loadNib:(NSString *)nibName inPlaceholder:(UIView *)placeholder
{
  UIView *nibView = [self viewFromNib:nibName];
  [nibView setFrame:placeholder.frame];
  [self.view insertSubview:nibView aboveSubview:placeholder];
  [placeholder removeFromSuperview];
  return nibView;
}

@end

Ответ 10

Я тоже хотел сделать что-то подобное, вот что я нашел: (SDK 3.1.3)

У меня есть контроллер A (сам принадлежит контроллеру Nav), который нажимает кнопку VC B на кнопку:

В AViewController.m

BViewController *bController = [[BViewController alloc] initWithNibName:@"Bnib" bundle:nil];
[self.navigationController pushViewController:bController animated:YES];
[bController release];

Теперь у VC B есть интерфейс от Bnib, но когда нажата кнопка, я хочу перейти в режим редактирования, который имеет отдельный пользовательский интерфейс из другого наконечника, но я не хочу, чтобы новый VC для режим редактирования, я хочу, чтобы новый nib был связан с моим существующим B VC.

Итак, в BViewController.m(в режиме нажатия кнопки)

NSArray *nibObjects = [[NSBundle mainBundle] loadNibNamed:@"EditMode" owner:self options:nil];
UIView *theEditView = [nibObjects objectAtIndex:0];
self.editView = theEditView;
[self.view addSubview:theEditView];

Затем на другой кнопке нажмите (чтобы выйти из режима редактирования):

[editView removeFromSuperview];

и я вернулся к своему оригинальному Bnib.

Это отлично работает, но обратите внимание, что у моего EditMode.nib есть только 1 верхний уровень obj, UIView obj. Не имеет значения, установлен ли владелец файла в этом nib как BViewController или NSObject по умолчанию, НО убедитесь, что View Outlet в File Owner не установлен ни на что. Если это так, то я получаю авария exc_bad_access и xcode переходит на загрузку 6677 кадров стека показывая внутренний метод UIView, который многократно называется... так выглядит как бесконечный цикл. (Однако, в моем оригинальном Bnib установлен параметр "Просмотр Outlet IS" )

Надеюсь, что это поможет.

Ответ 11

Я сделал категорию, которая мне нравится:

UIView+NibInitializer.h

#import <UIKit/UIKit.h>

@interface UIView (NibInitializer)
- (instancetype)initWithNibNamed:(NSString *)nibNameOrNil;
@end

UIView+NibInitializer.m

#import "UIView+NibInitializer.h"

@implementation UIView (NibInitializer)

- (instancetype)initWithNibNamed:(NSString *)nibNameOrNil
{
    if (!nibNameOrNil) {
        nibNameOrNil = NSStringFromClass([self class]);
    }
    NSArray *viewsInNib = [[NSBundle mainBundle] loadNibNamed:nibNameOrNil
                                                        owner:self
                                                      options:nil];
    for (id view in viewsInNib) {
        if ([view isKindOfClass:[self class]]) {
            self = view;
            break;
        }
    }
    return self;
}

@end

Затем вызовите вот так:

MyCustomView *myCustomView = [[MyCustomView alloc] initWithNibNamed:nil];

Используйте имя ниба, если ваш ниб назван чем-то другим, кроме имени вашего класса.

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

- (instancetype)initWithNibNamed:(NSString *)nibNameOrNil
{
    self = [super initWithNibNamed:nibNameOrNil];
    if (self) {
        self.layer.cornerRadius = CGRectGetHeight(self.bounds) / 2.0;
    }
    return self;
}

Ответ 12

В быстрой

На самом деле мое решение этой проблемы состояло в том, чтобы загрузить представление в viewDidLoad в моем CustonViewController, где я хотел использовать такое представление:

myAccessoryView = NSBundle.mainBundle().loadNibNamed("MyAccessoryView", owner: self, options: nil)[0] as! MyAccessoryView

Не загружать представление в метод loadView()! Метод loadView служит для загрузки представления для вашего пользовательского ViewController.

Ответ 13

Я нашел эту публикацию в блоге от Aaron Hillegass (автор, инструктор, Cocoa ниндзя), чтобы быть очень поучительным. Даже если вы не примете его модифицированный подход к загрузке файлов NIB через назначенный инициализатор, вы, вероятно, по крайней мере получите лучшее понимание процесса, который происходит. Я использовал этот метод в последнее время с большим успехом!

Ответ 14

Для пользователя Swift с условным параметром:

  • Создайте собственный UIView подкласс и xib файлы, который мы назовем после нашего собственного имени класса: в нашем случае MemeView. Внутри класса Meme View помните, чтобы определить его как назначаемый с атрибутом @IBDesignable перед объявлением класса
  • Rember установить владельца файлов в xib с помощью нашего пользовательского подкласса UIView в панели Insetity Inspector

    введите описание изображения здесь

  • В xib файле теперь мы можем построить наш интерфейс, создать ограничения, создать точки выхода, действия и т.д. введите описание изображения здесь

  • Нам нужно реализовать несколько методов для нашего пользовательского класса, чтобы открыть xib после инициализации

    class XibbedView: UIView {

    weak var nibView: UIView!
    
    override convenience init(frame: CGRect) {
        let nibName = NSStringFromClass(self.dynamicType).componentsSeparatedByString(".").last!
        self.init(nibName: nibName)
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        let nibName = NSStringFromClass(self.dynamicType).componentsSeparatedByString(".").last!
        let nib = loadNib(nibName)
        nib.frame = bounds
        nib.translatesAutoresizingMaskIntoConstraints = false
        addSubview(nib)
        nibView = nib
        setUpConstraints()
    }
    
    init(nibName: String) {
        super.init(frame: CGRectZero)
        let nibName = NSStringFromClass(self.dynamicType).componentsSeparatedByString(".").last!
        let nib = loadNib(nibName)
        nib.frame = bounds
        nib.translatesAutoresizingMaskIntoConstraints = false
        addSubview(nib)
        nibView = nib
        setUpConstraints()
    }
    
    func setUpConstraints() {
        ["V","H"].forEach { (quote) -> () in
            let format = String(format:"\(quote):|[nibView]|")
            addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(format, options: [], metrics: nil, views: ["nibView" : nibView]))
        }
    }
    
    func loadNib(name: String) -> UIView {
        let bundle = NSBundle(forClass: self.dynamicType)
        let nib = UINib(nibName: name, bundle: bundle)
        let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
    
        return view
    }
    

    }

  • В нашем пользовательском классе мы также можем определить некоторые свойства inspecableable, чтобы иметь полный контроль над ними из конструктора интерфейса

    @IBDesignable class MemeView: XibbedView {

    @IBInspectable var memeImage: UIImage = UIImage() {
        didSet {
            imageView.image = memeImage
        }
    }
    @IBInspectable var textColor: UIColor = UIColor.whiteColor() {
        didSet {
            label.textColor = textColor
        }
    }
    @IBInspectable var text: String = "" {
        didSet {
            label.text = text
        }
    }
    @IBInspectable var roundedCorners: Bool = false {
        didSet {
            if roundedCorners {
                layer.cornerRadius = 20.0
                clipsToBounds = true
            }
            else {
                layer.cornerRadius = 0.0
                clipsToBounds = false
            }
        }
    }
    
    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var imageView: UIImageView!
    

}

Несколько примеров:
введите описание изображения здесь введите описание изображения здесь

Если нам нужно добавить дополнительную информацию, представление пока отображается внутри раскадровки или другого xib, чтобы сделать это, мы можем реализовать prepareForInterfaceBuilder(), этот метод будет выполняться только при открытии файла в построителе интерфейса. Если вы сделали все, что я написал, но ничего не работало, это способ отладить представление sigle путем добавления контрольных точек в его реализации. введите описание изображения здесь
Вот иерархия представлений. Просмотр hiearchy

Надеюсь, что это поможет получить полную выборку здесь

Ответ 15

В предыдущем ответе не учитывается изменение структуры NIB (XIB), которая произошла между 2.0 и 2.1 iPhone SDK. Теперь содержимое пользователя начинается с индекса 0 вместо 1.

Вы можете использовать макрос 2.1, который действителен для всех версий 2.1 и выше (что два символа подчеркивания перед IPhone:

 // Cited from previous example
 NSArray* nibViews =  [[NSBundle mainBundle] loadNibNamed:@"QPickOneView" owner:self options:nil];
 int startIndex;
 #ifdef __IPHONE_2_1
 startIndex = 0;
 #else
 startIndex = 1;
 #endif
 QPickOneView* myView = [ nibViews objectAtIndex: startIndex];
 myView.question = question;

Мы используем технику, подобную этой для большинства наших приложений.

Барни

Ответ 16

У меня были причины делать то же самое (программно загружая представление из XIB файла), но мне нужно было сделать это полностью из контекста подкласса подкласса UIView (т.е. без привлечения контроллера вида в любом случае). Для этого я создал этот метод утилиты:

+ (id) initWithNibName:(NSString *)nibName withSelf:(id)myself {

    NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:nibName
                                                    owner:myself options:nil];
    for (id object in bundle) {
        if ([object isKindOfClass:[myself class]]) {
            return object;
        }
    }  

    return nil;
} 

Затем я вызываю его из моего подкласса initWithFrame следующим образом:

- (id)initWithFrame:(CGRect)frame {

    self = [Utilities initWithNibName:@"XIB1" withSelf:self];
    if (self) {
        // Initialization code.
    }
    return self;
}

Опубликовано для общего интереса; если кто-нибудь видит какие-либо проблемы, не делая этого таким образом, пожалуйста, дайте мне знать.

Ответ 17

Вот способ сделать это в Swift (в настоящее время пишут Swift 2.0 в XCode 7 beta 5).

В подклассе UIView, который вы задали как "Пользовательский класс" в построителе интерфейса, создайте такой метод (мой подкласс называется RecordingFooterView):

class func loadFromNib() -> RecordingFooterView? {
    let nib = UINib(nibName: "RecordingFooterView", bundle: nil)
    let nibObjects = nib.instantiateWithOwner(nil, options: nil)
    if nibObjects.count > 0 {
        let topObject = nibObjects[0]
        return topObject as? RecordingFooterView
    }
    return nil
}

Затем вы можете просто называть его следующим образом:

let recordingFooterView = RecordingFooterView.loadFromNib()

Ответ 18

Ни один из ответов не объясняет, как создать самостоятельный XIB, который является корнем этого вопроса. Нет опции Xcode 4 для "Создать новый файл XIB".

Для этого

1) Choose "New File..."
2) Choose the "User Interface" category under the iOS section
3) Choose the "View" item
4) You will then be prompted to choose an iPhone or iPad format

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

Ответ 19

@AVeryDev

6) Чтобы подключить загруженное представление к виду контроллера просмотра:

[self.view addSubview:myViewFromNib];

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

Чтобы уточнить: контроллер представления имеет несколько IBOutlets, некоторые из которых связаны с элементами исходного файла nib (как обычно), а некоторые связаны с элементами загруженного nib. Оба nib имеют один и тот же класс владельца. Загруженный вид накладывается на оригинал.

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

Ответ 20

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

1) Создайте класс myCustomView, унаследованный от UIView.
введите описание изображения здесь

2) Создайте .xib с именем myCustomView.
введите описание изображения здесь

3) Измените класс UIView внутри вашего .xib файла, назначьте класс myCustomView.
введите описание изображения здесь

4) Создайте IBOutlets
введите описание изображения здесь

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

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

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

Ответ 21

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

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

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

    MyView * myView = [MyView nib_viewFromNibWithOwner: владелец];

Здесь категория для этого:

@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 {

}

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

Ответ 22

Кратчайшая версия:

RSFavoritePlaceholderView *favoritePlaceholderView = [[[NSBundle mainBundle] loadNibNamed:@"RSFavoritePlaceholderView" owner:self options:nil] firstObject];

Ответ 23

В итоге я добавил категорию 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