我试着做一些复杂的事情,但应该是可能的。所以这里有一个对你们所有专家的挑战(这个论坛是由你们很多人组成的:))。

我正在创建一个问卷“组件”,我想加载在一个navigationcontroller(我的QuestionManagerViewController)。“组件”是一个“空的”UIViewController,它可以根据需要回答的问题加载不同的视图。

我的做法是:

Create Question1View object as a UIView subclass, defining some IBOutlets. Create (using Interface Builder) the Question1View.xib (HERE IS WHERE MY PROBLEM PROBABLY IS). I set both the UIViewController and the UIView to be of class Question1View. I link the outlets with the view's component (using IB). I override the initWithNib of my QuestionManagerViewController to look like this: - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { if (self = [super initWithNibName:@"Question1View" bundle:nibBundleOrNil]) { // Custom initialization } return self; }

当我运行代码时,我得到这个错误:

2009-05-14 15:05:37.152 iMobiDines[17148:20b] ***由于未捕获异常'NSInternalInconsistencyException'而终止应用程序,原因:'-[UIViewController _loadViewFromNibNamed:bundle:] loaded the "Question1View" nib but the view outlet was not set.'

我确信有一种方法可以使用nib文件加载视图,而不需要创建一个viewController类。


当前回答

没有一个答案解释如何创建独立的XIB,这是这个问题的根源。Xcode 4没有“创建新的XIB文件”选项。

要做到这一点

1) Choose "New File..."
2) Choose the "User Interface" category under the iOS section
3) Choose the "View" item
4) You will then be prompted to choose an iPhone or iPad format

这看起来很简单,但它可以为您节省几分钟的时间,因为“XIB”这个词没有出现在任何地方。

其他回答

我有理由做同样的事情(从XIB文件编程加载一个视图),但我需要完全从一个UIView的子类的子类的上下文(即不涉及视图控制器的任何方式)。为了做到这一点,我创建了这个实用方法:

+ (id) initWithNibName:(NSString *)nibName withSelf:(id)myself {

    NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:nibName
                                                    owner:myself options:nil];
    for (id object in bundle) {
        if ([object isKindOfClass:[myself class]]) {
            return object;
        }
    }  

    return nil;
} 

然后我从我的子类的initWithFrame方法调用它,如下所示:

- (id)initWithFrame:(CGRect)frame {

    self = [Utilities initWithNibName:@"XIB1" withSelf:self];
    if (self) {
        // Initialization code.
    }
    return self;
}

张贴的一般利益;如果有人发现没有这样做的问题,请告诉我。

还有一种更简单的方法来访问视图,而不是将nib作为数组处理。

1)创建一个自定义的View子类,其中包含你以后想要访问的任何出口。——MyView

2)在你想要加载和处理nib的UIViewController中,创建一个IBOutlet属性来保存加载的nib的视图

在MyViewController中(一个UIViewController子类)

  @property (nonatomic, retain) IBOutlet UIView *myViewFromNib;

(别忘了合成它并在你的。m文件中发布它)

3)在IB中打开你的nib(我们称之为'myViewNib.xib'),设置你文件的所有者为MyViewController

4)现在连接你的文件的所有者出口myViewFromNib到nib的主视图。

5)现在在MyViewController中,写以下一行:

[[NSBundle mainBundle] loadNibNamed:@"myViewNib" owner:self options:nil];

当你这样做的时候,把你的财产称为“自我”。myViewFromNib”将让你从你的nib访问视图!

我做了一个我喜欢的分类:

UIView + NibInitializer.h

#import <UIKit/UIKit.h>

@interface UIView (NibInitializer)
- (instancetype)initWithNibNamed:(NSString *)nibNameOrNil;
@end

UIView + NibInitializer.m

#import "UIView+NibInitializer.h"

@implementation UIView (NibInitializer)

- (instancetype)initWithNibNamed:(NSString *)nibNameOrNil
{
    if (!nibNameOrNil) {
        nibNameOrNil = NSStringFromClass([self class]);
    }
    NSArray *viewsInNib = [[NSBundle mainBundle] loadNibNamed:nibNameOrNil
                                                        owner:self
                                                      options:nil];
    for (id view in viewsInNib) {
        if ([view isKindOfClass:[self class]]) {
            self = view;
            break;
        }
    }
    return self;
}

@end

然后,像这样调用:

MyCustomView *myCustomView = [[MyCustomView alloc] initWithNibNamed:nil];

如果你的nib不是你的类名,请使用一个nib名。

为了在你的子类中覆盖它以获得额外的行为,它可以看起来像这样:

- (instancetype)initWithNibNamed:(NSString *)nibNameOrNil
{
    self = [super initWithNibNamed:nibNameOrNil];
    if (self) {
        self.layer.cornerRadius = CGRectGetHeight(self.bounds) / 2.0;
    }
    return self;
}

我发现Aaron Hillegass(作者,讲师,可可忍者)的这篇博客非常有启发性。即使您不采用他修改后的方法通过指定的初始化器加载NIB文件,您也至少可以更好地理解正在进行的过程。我最近一直在用这个方法,而且非常成功!

下面是一种在Swift中实现的方法(目前正在XCode 7 beta 5中编写Swift 2.0)。

从你在接口构建器中设置为“自定义类”的UIView子类中创建一个像这样的方法(我的子类叫做RecordingFooterView):

class func loadFromNib() -> RecordingFooterView? {
    let nib = UINib(nibName: "RecordingFooterView", bundle: nil)
    let nibObjects = nib.instantiateWithOwner(nil, options: nil)
    if nibObjects.count > 0 {
        let topObject = nibObjects[0]
        return topObject as? RecordingFooterView
    }
    return nil
}

然后你可以像这样调用它:

let recordingFooterView = recordingFooterView . loadfromnib ()