UIView та initWithFrame та файл NIB. Як я можу завантажити файл NIB?


75

У мене є телефонний UIViewдзвінок, baseViewі я маю, initWithFrameде я додаю деякі інші подання та роблю власні речі. Те саме представлення також має файл NIB.

Тепер у мене є UIViewControllerклас з іменем, AppControllerв якому я хочу додати baseViewподання до подання AppControllerподання, тому я роблю це:

self.view = baseView;але проблема в тому, що файл NIB не завантажується. Як переконатись, що налаштовані матеріали та файл NIB завантажуються / запускаються?

Відповіді:


167

У вас є багато варіантів, залежно від того, як ваш клас "baseView" призначений для використання та інтеграції у вашу програму. Незрозуміло, як ви збираєтеся використовувати цей клас - оскільки подання в підкласі UIViewController або як багаторазовий модульний компонент означають створювати кілька разів у вашому додатку для використання у багатьох різних контролерах перегляду.

Якщо ваш вигляд має бути єдиним поданням у підкласі UIViewController, тоді Phonitive правильний - об’єднайте його разом із файлом .xib підкласу UIViewController та використовуйте viewDidLoad UIViewController для остаточної ініціалізації.

Але якщо ви хочете, щоб ваш клас View був підкомпонентом, який повторно використовувався кілька разів у різних контролерах подання, інтегрований або за допомогою коду, або за допомогою включення у файл .xib для іншого контролера, тоді вам потрібно реалізувати як initWithFrame: init метод, так і awakeFromNib, вирішити обидві справи. Якщо ваша внутрішня ініціалізація завжди включає деякі об'єкти з .xib, то у вашому initWithFrame вам потрібно буде завантажити .xib вручну, щоб підтримати класи "замовника", які хочуть створити ваш віджет за допомогою коду. І так само, якщо файл .xib містить ваш об’єкт, то вам потрібно буде переконатися, що ви викликаєте будь-який необхідний код для завершення з awakeFromNib.

Ось приклад того, як створити компонент підкласу UIView з дизайном інтерфейсу користувача в перо.

MyView.h:

@interface MyView : UIView
{
    UIView *view;
    UILabel *l;
}
@property (nonatomic, retain) IBOutlet UIView *view;
@property (nonatomic, retain) IBOutlet UILabel *l;

MyView.m:

#import "MyView.h"
@implementation MyView
@synthesize l, view;

- (id)initWithFrame:(CGRect)frame 
{
    self = [super initWithFrame:frame];
    if (self) 
    {
        // Initialization code.
        //
        [[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self options:nil];
        [self addSubview:self.view];
    }
    return self;
}

- (void) awakeFromNib
{
    [super awakeFromNib];

    // commenters report the next line causes infinite recursion, so removing it
    // [[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self options:nil];
    [self addSubview:self.view];
}

- (void) dealloc
{
     [l release];
     [view release];
     [super dealloc];
}

Ось як виглядає файл nib (за винятком того, що власника файлу потрібно змінити на клас MyView).

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

обов’язково підключіть і вигляд, і розетки міток до власника файлу. Це воно! Шаблон для створення віджетів для повторного використання UIView.

По-справжньому акуратно в цій структурі є те, що ви можете розміщувати екземпляри об’єкта MyView в інших файлах ніб, просто розмістіть UIView у потрібному розташуванні / розмірі, а потім змініть клас в інспекторі ідентифікації (CMD-4) на MyView, і бум, у вас є екземпляр вашого віджета в будь-яких переглядах, які ви хочете! Подібно до об'єктів UIKit, ви можете реалізовувати протоколи делегатів, щоб об'єкти, які використовують ваш віджет, могли отримувати сповіщення про цікаві події та надавати дані для відображення у віджеті для його налаштування.


1
Зазвичай, коли я створюю програму, мені подобається створювати деякі подання, і я хочу використовувати ці подання в контролері перегляду. Я не хочу створювати контролер перегляду для кожного перегляду, тому я створюю окремі подання, які я хочу включити у подання контролера перегляду.
dbrasco

2
Мені подобається той факт, що ви говорите, що я можу реалізувати initWithFrame та awakeFromNib, але я не впевнений, яку ініціалізацію я повинен зробити і в якому порядку. Не могли б ви навести приклад? Скажімо, я додав деякі мітки та кнопки в XIB із IB. У моєму поданні є кілька IBOutlets. Тепер я хочу, щоб initWithFrame зробив щось із цим об’єктом. Як би я ініціював перегляд із NIB, щоб він знав про ці об'єкти?
dbrasco

2
Справді. Звичайно, є кілька випадків, коли я можу просто підсунути інший вигляд VC + на навігаційний контролер, але це не завжди так. Тепер мені потрібно перечитати про IBPlugins, f'rinstance: cocoawithlove.com/2009/07/… (зачекайте, ні, не для iOS, але все ж ...)
Джо Д'Андреа,

5
loadNibNamed inside awakeFromNib викликає нескінченну рекурсію
Гарго

1
Це правда, @Gargo правильний, я просто тестував цей код (чудова відповідь), але я вводив нескінченний цикл при ініціалізації, після видалення loadNibNamed всередині awaleFromNib ця проблема зупинилася. Дякую.
Осфо,

3

Я знайшов цю публікацію після проблеми зі спробою зробити це у своєму додатку. Я намагався створити екземпляр подання з NIB у методі ViewDidLoad, але елементи керування діяли так, ніби їх було вимкнено. Я боровся з цим, намагаючись безпосередньо встановити властивість userInteractionEnabled і програмно встановити селектор сенсорної події для кнопки в цьому поданні. Нічого не працювало. Я наткнувся на інший допис і виявив, що viewDidLoad, мабуть, занадто рано, щоб завантажувати цей NIB. Я перемістив навантаження до методу ViewWillAppear, і все запрацювало. Сподіваюся, це допомагає комусь іншому боротися з цим. Основна відповідь була чудовою і добре працює для мене зараз, коли мені це телефонують з належного місця.


1
Поділіться з нами посиланням на цю іншу публікацію.

Ймовірно, він наводить stackoverflow.com/a/819265/779419 . Під час створення екземпляра власного подання переконайтеся, що ви фактично використовуєте initWithFrame із належним CGRect.
schieferstapel

2

якщо ви хочете використовувати NIB, краще, щоб ваш UIView був зв'язаний з UIViewController, в цьому випадку ви можете використовувати

UIViewController *vc=[[UIViewController alloc] initWithNibName:@"YourNIBWihtOUTEXTENSION" bundle:nil]

[self.view addSubView:vc.view ];

остерігаючись витоків пам'яті, ви повинні звільнити vc


Неправда; Якщо вам потрібно змінити вміст UIView за допомогою Interface Builder, вам потрібно буде скористатися методом Богатиря. Причина, по якій вам доведеться використовувати UIView спільно з Nib, полягає в тому, що Apple не рекомендує використовувати вкладені UIViewControllers, оскільки батьківські дзвінки можуть зламатися. Тобто , якщо ваш підтримувати <IOS 5. stackoverflow.com/questions/1141015 / ...
Ospho

Це не найкраща реалізація - я б дослідив контейнер vcs
Адам Уейт

0

Якщо у вас є власний UIView із файлом xib.

- (id)initWithFrame:(CGRect)frame
{
   self = [super initWithFrame:frame];

   id mainView;
   if (self)
   {
       NSArray *subviewArray = [[NSBundle mainBundle] loadNibNamed:@"HomeAllAdsView" owner:self options:nil];
       mainView = [subviewArray objectAtIndex:0];    
   }
   return mainView;
}

- (void) awakeFromNib
{
   [super awakeFromNib];
}

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.