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

问题描述 投票:21回答:3

我熟悉为我自己的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]; 

在此先感谢您的任何帮助。

ios uiview init iboutlet loadnibnamed
3个回答
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类。 在选择视图后,在界面构建器的右侧部分的第三个选项卡上定义


7
投票

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


2
投票

这是我使用的一种方法:

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