iOS加载Nib命名混乱,什么是最佳实践



我熟悉为自己的UIView子类创建XIB的大部分过程,但并不是所有东西都能正常工作——这主要与IBOutlets的链接有关。我可以用一种迂回的方式让他们工作。

我的设置是:

  • 我有MyClass.h和MyClass.m。它们有用于UIView(称为view)和UILabel(称为myLabel)的IBOutlets。我添加了"view"属性,因为网上的一些示例似乎表明你需要它,它实际上解决了一个问题,即我因为找不到view属性而崩溃,我想甚至在UIView父类中也找不到
  • 我有一个名为MyClass.XIB的XIB文件,它的file的所有者自定义类是MyClass,它在该类的.h和.m之后正确地预填充

我的init方法是我遇到问题的地方。

我尝试使用NSBundle mainBundle的"loadNibNamed"方法,并将所有者设置为"self",希望我能创建一个视图实例,它会自动将其出口与我的类中的出口匹配(我知道如何做到这一点,而且我很小心)。然后我想我想让"self"等于笔尖中索引0处的子视图,而不是进行

self = [super init];

或者类似的东西。

我感觉我在这里做错了,但网上的例子在init方法中也发生了类似的事情,但他们将子视图0分配给视图属性,并将其作为子视图添加,但这不是总共两个MyClass实例吗?其中一个基本上未链接到IBOutlets,包含通过loadNibNamed实例化的子MyClass?或者充其量,它不是一个带有额外中介UIView的MyClass实例吗?UIView包含我最初想要作为MyClass的直接子级的所有IBOutlets?当涉及到instanceOfMyClass.frame.size.width之类的事情时,这会带来一些小麻烦,因为它返回0,而引入的子UIView返回我想要的实际帧大小。

我做错的是在init方法中扰乱loadNibNamed吗?我应该做更像这样的事情吗?

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类的。在您选择视图后,在界面构建器右侧的第三个选项卡上定义

您所需要做的就是通过loadNibNamed创建子视图,设置框架,并将其添加到子视图中。例如,我使用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];
}

我最初建议使用控制器,我将在下面保留这个答案以供历史参考。


原始答案:

我在这里看不到任何对视图控制器的引用。通常你会有一个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创建一个子类,它将被称为MyClass
  2. 创建视图xib文件。在接口生成器中打开,单击"文件的所有者",然后在"标识检查器"中更改类到您的父视图控制器,例如。ParentViewController
  3. 单击对象列表中已有的视图并更改其类转换为MyClass
  4. 您在MyClass中声明的任何出口/行动通过从"视图"(而不是"文件的所有者")中单击并拖动连接。如果要将它们连接到ParentViewController中的变量,请单击"文件所有者"中的"拖动">
  5. 现在,在ParentViewController中,您需要声明一个实例CCD_ 22的变量

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

最新更新