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

我正在创建一个问卷“组件”,我想加载在一个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类。


当前回答

前面的答案没有考虑iPhone SDK 2.0到2.1之间发生的NIB (XIB)结构的变化。用户内容现在从索引0开始,而不是1。

你可以使用2.1宏,它适用于所有2.1及以上版本(在IPHONE前面加两个下划线):

 // Cited from previous example
 NSArray* nibViews =  [[NSBundle mainBundle] loadNibNamed:@"QPickOneView" owner:self options:nil];
 int startIndex;
 #ifdef __IPHONE_2_1
 startIndex = 0;
 #else
 startIndex = 1;
 #endif
 QPickOneView* myView = [ nibViews objectAtIndex: startIndex];
 myView.question = question;

我们在大多数应用程序中都使用类似的技术。

巴尼

其他回答

这是一件应该比较容易的事情。我最终扩展了UIViewController并添加了一个loadNib:inPlaceholder: selector。现在我可以说

self.mySubview = (MyView *)[self loadNib:@"MyView" inPlaceholder:mySubview];

下面是这个类别的代码(它和Gonso描述的一样):

@interface UIViewController (nibSubviews)

- (UIView *)viewFromNib:(NSString *)nibName;
- (UIView *)loadNib:(NSString *)nibName inPlaceholder:(UIView *)placeholder;

@end

@implementation UIViewController (nibSubviews)

- (UIView *)viewFromNib:(NSString *)nibName
{
  NSArray *xib = [[NSBundle mainBundle] loadNibNamed:nibName owner:self options:nil]; 
  for (id view in xib) { // have to iterate; index varies
    if ([view isKindOfClass:[UIView class]]) return view;
  }
  return nil;
}

- (UIView *)loadNib:(NSString *)nibName inPlaceholder:(UIView *)placeholder
{
  UIView *nibView = [self viewFromNib:nibName];
  [nibView setFrame:placeholder.frame];
  [self.view insertSubview:nibView aboveSubview:placeholder];
  [placeholder removeFromSuperview];
  return nibView;
}

@end

你也可以使用UIViewController的initWithNibName而不是loadnibname。我发现这样更简单。

UIViewController *aViewController = [[UIViewController alloc] initWithNibName:@"MySubView" bundle:nil];
[self.subview addSubview:aViewController.view];
[aViewController release];  // release the VC

现在你只需要创建MySubView。xib和MySubView.h/m。在MySubView。xib设置文件的Owner类为UIViewController,视图类为MySubView。

您可以使用父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;
}

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

下面是一种在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 ()

这是一个很好的问题(+1),答案几乎是有帮助的;)抱歉,伙计们,虽然Gonso和AVeryDev都给出了很好的提示,但我花了很长时间才读完这篇文章。希望这个答案能帮助到其他人。

MyVC是持有这些东西的视图控制器。

MySubview是我们想从xib中加载的视图

In MyVC.xib, create a view of type MySubView that is the right size & shape & positioned where you want it. In MyVC.h, have IBOutlet MySubview *mySubView // ... @property (nonatomic, retain) MySubview *mySubview; In MyVC.m, @synthesize mySubView; and don't forget to release it in dealloc. In MySubview.h, have an outlet/property for UIView *view (may be unnecessary, but worked for me.) Synthesize & release it in .m In MySubview.xib set file owner type to MySubview, and link the view property to your view. Lay out all the bits & connect to the IBOutlet's as desired Back in MyVC.m, have NSArray *xibviews = [[NSBundle mainBundle] loadNibNamed: @"MySubview" owner: mySubview options: NULL]; MySubview *msView = [xibviews objectAtIndex: 0]; msView.frame = mySubview.frame; UIView *oldView = mySubview; // Too simple: [self.view insertSubview: msView aboveSubview: mySubview]; [[mySubview superview] insertSubview: msView aboveSubview: mySubview]; // allows nesting self.mySubview = msView; [oldCBView removeFromSuperview];

对我来说棘手的一点是:其他答案中的提示从xib加载了我的视图,但没有替换MyVC中的视图(呸!)——我必须自己交换。

同样,为了访问mySubview的方法,.xib文件中的view属性必须设置为mySubview。否则,它会返回一个普通的UIView。

如果有一种方法来加载mySubview直接从它自己的xib,那将摇滚,但这让我在我需要的地方。