我熟悉为自己的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
的子类)。
这里有一个我使用的方法:
- 为
UIView
创建一个子类,它将被称为MyClass
- 创建视图xib文件。在接口生成器中打开,单击"文件的所有者",然后在"标识检查器"中更改类到您的父视图控制器,例如。
ParentViewController
- 单击对象列表中已有的视图并更改其类转换为
MyClass
- 您在
MyClass
中声明的任何出口/行动通过从"视图"(而不是"文件的所有者")中单击并拖动连接。如果要将它们连接到ParentViewController
中的变量,请单击"文件所有者"中的"拖动"> - 现在,在
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];
}