IOS loadNibNamed путаница, что лучше всего?
Я знаком с большинством процессов создания XIB для моего собственного подкласса UIView, но не все работает правильно для меня - это в основном связано с привязкой IBOutlets. Я могу заставить их работать в том, что кажется окольным путем.
Моя настройка такова:
- У меня есть MyClass.h и MyClass.m. У них есть IBOutlets для UIView (называемый view) и UILabel (называемый myLabel). Я добавил свойство "view", потому что некоторые примеры в Интернете, казалось, подсказывали вам, что вам это нужно, и он фактически решил проблему, когда я получал сбой, потому что он не смог найти свойство view, я думаю, что даже в родительском классе UIView.
- У меня есть XIB файл с именем MyClass.xib, а его собственный пользовательский класс File Owner - MyClass, который предварительно заполнен после моих .h и .m для этого класса.
Мой метод init - это то, где у меня возникают проблемы.
Я попытался использовать NSBundle mainBundle 'loadNibNamed' метод и установить владельца на "я", надеясь, что я создам экземпляр представления, и он автоматически получит свои выходные данные, соответствующие тем, которые были в моем классе (Я знаю, как это сделать, и я осторожен с этим). Затем я подумал, что хочу сделать "я" равным подчиненному в индексе 0 в этом nib, вместо того, чтобы делать
self = [super init];
или что-то в этом роде.
Я чувствую, что я делаю что-то неправильно здесь, но примеры в Интернете имеют похожие вещи в методе init, но они присваивают этому subview 0 свойству вида и добавляют его как дочерний элемент - но это не то в общей сложности два экземпляра MyClass? Один по существу несвязанный с IBOutlets, содержащий дочерний MyClass, созданный с помощью loadNibNamed? Или, в лучшем случае, разве это не экземпляр MyClass с дополнительным промежуточным UIView, содержащим все IBOutlets, которые я первоначально хотел как прямые дети MyClass? Это вызывает небольшое раздражение, когда дело касается таких вещей, как instanceOfMyClass.frame.size.width, поскольку он возвращает 0, когда введенный дочерний UIView возвращает реальный размер кадра, который я искал.
Это то, что я делаю неправильно, что я возился с loadNibNamed внутри метода init? Должен ли я делать что-то подобное?
MyClass *instance = [[MyClass alloc] init];
[[NSBundle mainBundle] loadNibNamed:@"MyClass" owner:instance options:nil];
Или как это?
MyClass *instance = [[[NSBundle mainBundle] loadNibNamed:@"MyClass" owner:nil options:nil] objectAtIndex:0];
Спасибо за любую помощь.
Ответы
Ответ 1
Второй вариант правильный. Самый защитный код, который вы можете сделать, выглядит следующим образом:
+ (id)loadNibNamed:(NSString *)nibName ofClass:(Class)objClass {
if (nibName && objClass) {
NSArray *objects = [[NSBundle mainBundle] loadNibNamed:nibName
owner:nil
options:nil];
for (id currentObject in objects ){
if ([currentObject isKindOfClass:objClass])
return currentObject;
}
}
return nil;
}
И вызывается вот так:
MyClass *myClassInstance = [Utility loadNibNamed:@"the_nib_name"
ofClass:[MyClass class]];
// In my case, the code is in a Utility class, you should
// put it wherever it fits best
Я предполагаю, что ваш MyClass является подклассом UIView
? Если это так, то вам нужно убедиться, что UIView
вашего .xib действительно принадлежит классу MyClass. Это определено на третьей вкладке правой части в построителе интерфейса, после выбора вида
Ответ 2
Все, что вам нужно сделать, - создать subview через loadNibNamed
, установить фрейм и добавить его в подвью. Например, я добавляю три подзаголовка, используя мой класс MyView
, который является подклассом UIView
, интерфейс которого определен в NIB, MyView.xib
:
Итак, я определяю initWithFrame
для моего подкласса UIView
:
- (id)initWithFrame:(CGRect)frame
{
NSLog(@"%s", __FUNCTION__);
self = [super initWithFrame:frame];
if (self)
{
NSArray *nibContents =
[[NSBundle mainBundle] loadNibNamed:@"MyView"
owner:self
options:nil];
[self addSubview:nibContents[0]];
}
return self;
}
Итак, например, в моем UIViewController
, я могу загрузить несколько таких объектов с подклассом UIView
, например:
for (NSInteger i = 0; i < 3; i++)
{
CGRect frame = CGRectMake(0.0, i * 100.0 + 75.0, 320.0, 100.0);
MyView *myView = [[MyView alloc] initWithFrame:frame];
[self.view addSubview:myView];
// if you want, do something with it:
// Here I'm initializing a text field and label
myView.textField.text = [NSString stringWithFormat:@"MyView textfield #%d",
i + 1];
myView.label.text = [NSString stringWithFormat:@"MyView label #%d",
i + 1];
}
Сначала я посоветовал использовать контроллеры использования, и я опишу этот ниже ответ на историческую справку.
Оригинальный ответ:
Здесь я не вижу ссылок на контроллеры представлений. Обычно у вас есть подкласс UIViewController
, который вы затем создаете с помощью
MyClassViewController *controller =
[[MyClassViewController alloc] initWithNibName:@"MyClass"
bundle:nil];
// then you can do stuff like
//
// [self presentViewController:controller animated:YES completion:nil];
В файле NIB MyClass.xib
можно указать базовый класс для UIView
, если вы хотите, где у вас есть весь код, связанный с представлением (например, предполагая, что MyClass был подклассом UIView
).
Ответ 3
Здесь один метод, который я использую:
- Создайте подкласс для
UIView
, это будет называться MyClass
- Создайте xib файл вида. Открыть в интерфейсе,
щелкните File Owner и в Identity Inspector, измените класс
к контроллеру родительского представления, например.
ParentViewController
.
- Нажмите на представление уже в списке объектов и измените его.
класса в Identity Inspector до
MyClass
.
- Любые выпуски/действия, которые вы объявляете в
MyClass
, будут
связанный перетаскиванием по клику из представления (не владельца файла). Если вы хотите связать их с переменными из ParentViewController
, тогда перетащите мышью из файла Owner.
- Теперь в вашем
ParentViewController
вам нужно объявить экземпляр
переменная для MyClass
.
ParentViewController.h
добавьте следующее:
@class MyClass
@interface ParentViewController : UIViewController {
MyClass *myClass;
}
@property (strong, nonatomic) MyClass *myClass;
Синтезируйте это в своей реализации и добавьте следующее в свой viewDidLoad
метод:
- (void)viewDidLoad {
[super viewDidLoad];
[[NSBundle mainBundle] loadNibNamed:@"MyClass" owner:self options:nil];
self.myClass.frame = CGRectMake(X,Y,W,H); //put your values in.
[self.view addSubview:self.myClass];
}