iOS loadNibName混淆,什么是最佳做法?

我熟悉为我自己的UIView子类创buildXIB的大部分过程,但并不是所有事情都适合我,主要是与IBOutlets连接起来。 我可以让他们看起来像一个迂回的方式工作。

我的设置是这样的:

  • 我有MyClass.h和MyClass.m。 他们有一个UIView(称为视图)和一个UILabel(称为myLabel)的IBOutlets。 我添加了“视图”属性,因为在线上的一些示例似乎表明你需要这个,它实际上解决了一个问题,因为它无法find视图属性,我猜甚至在UIView父类。
  • 我有一个名为MyClass.xib的XIB文件,它的文件所有者自定义类是MyClass,它在我的.h和.m文件存在之后正确预先填充。

我的init方法是我有问题的地方。

我尝试使用NSBundle的mainBundle的“loadNibNamed”方法,并将所有者设置为“自我”,希望我会创build视图的实例,它会自动得到它的出口匹配到我的课(我知道如何做到这一点,我很小心)。 然后我想我想让自己等于那个笔尖的索引0处的子视图,而不是这样做

self = [super init]; 

或类似的东西。

我觉得我在这里做错了,但在线示例在init方法中有类似的事情,但他们将该子视图0分配给视图属性,并添加它作为一个孩子 – 但是那不是总共两个MyClass实例? 一个基本上与IBOutlets无关,包含通过loadNibNamed实例化的子MyClass? 或者至多,是不是一个MyClass实例与一个额外的中介UIView包含我最初希望作为MyClass的直接子项目的所有IBOutlets? 当涉及到像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]; 

预先感谢任何帮助。

第二个选项是正确的。 你可以做的最防守的代码是这样的:

 + (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的子类? 如果是这种情况,那么你需要确保你的.xib的UIView实际上是MyClass类。 在select视图后,在界面构build器右侧的第三个选项卡上定义

所有你需要做的是通过loadNibNamed创build子视图,设置框架,并将其添加到子视图。 例如,我使用我的MyView类添加了三个子视图,它是一个UIView子类,其接口在NIB MyView.xib定义:

所以,我为我的UIView子类定义了initWithFrame

 - (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]; } 

我最初build议使用控制器,我会保留下面的答案以供历史参考。


原始答案:

在这里我没有看到任何对视图控制器的引用。 通常你会有一个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的子类)。

以下是我使用的一种方法:

  1. UIView创build一个子类,这将被称为MyClass
  2. 创build一个视图xib文件。 在界面生成器中打开,单击文件的所有者,然后在Identity Inspector中,将类更改为父视图控制器的类,例如ParentViewController
  3. 单击对象列表中已有的视图,并将其在Identity Inspector中的类更改为MyClass
  4. 您在MyClass声明的任何出口/操作将通过从视图(而非文件所有者)中单击拖动来进行连接。 如果你想把它们连接到来自ParentViewControllervariables,然后点击从文件的所有者。
  5. 现在在你的ParentViewController你需要为MyClass声明一个实例variables。

ParentViewController.h添加以下内容:

 @class MyClass @interface ParentViewController : UIViewController { MyClass *myClass; } @property (strong, nonatomic) MyClass *myClass; 

在你的实现中合成这个,并在你的viewDidLoad方法中join以下内容:

 - (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]; }