iOS loadNibNamed混乱,最佳做法是什么?

时间:2012-11-23 18:58:03

标签: ios uiview init iboutlet loadnibnamed

我熟悉为我自己的UIView子类创建XIB的大部分过程,但并非所有内容都适合我 - 它主要与IBOutlets链接有关。我可以让他们以看似迂回的方式工作。

我的设置是:

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

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

我尝试使用NSBundle mainBundle的'loadNibNamed'方法并将所有者设置为'self',希望我创建一个视图实例,它会自动将其出口与我班级中的出口相匹配(我知道怎么做,我很小心)。然后我想我想让'self'等于那个nib中索引0的子视图,而不是做

self = [super init];

或类似的东西。

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

提前感谢您的任何帮助。

3 个答案:

答案 0 :(得分:23)

第二个选项是正确的。您可以做的最具防御性的代码是这样的:

+ (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类。在选择视图

后,在界面构建器的右侧部分的第三个选项卡上定义

答案 1 :(得分:7)

您需要做的就是通过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是{的子类{1}})。

答案 2 :(得分:2)

这是我使用的一种方法:

  1. UIView创建一个子类,这将被称为MyClass
  2. 创建一个视图xib文件。在界面构建器中打开, 单击文件的所有者,然后在Identity Inspector中更改类 到父视图控制器的那个,例如 ParentViewController
  3. 单击对象列表中已有的视图并进行更改 Identity Inspector中的类MyClass
  4. 您在MyClass中声明的任何商店/行动都将是 通过从View(而不是File的所有者)单击拖动来连接。如果要将它们连接到ParentViewController的变量,请从文件所有者单击并拖动。
  5. 现在在您的ParentViewController中,您需要声明一个实例 MyClass的变量。
  6. 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];
    }