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

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


当前回答

对于那些需要管理多个自定义视图实例的人,也就是Outlet Collection,我合并并定制了@Gonso, @AVeryDev和@Olie的答案:

Create a custom MyView : UIView and set it as "Custom Class" of the root UIView in the desired XIB; Create all outlets you need in MyView (do it now because after point 3 the IB will propose you to connect outlets to the UIViewController and not to the custom view as we want); Set your UIViewController as "File's Owner" of the custom view XIB; In the UIViewController add a new UIViews for each instance of MyView you want, and connect them to UIViewController creating an Outlet Collection: these views will act as "wrapper" views for the custom view instances; Finally, in the viewDidLoad of your UIViewController add the following lines:

NSArray *bundleObjects; MyView *currView; NSMutableArray *myViews = [NSMutableArray arrayWithCapacity:myWrapperViews.count]; for (UIView *currWrapperView in myWrapperViews) { bundleObjects = [[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self options:nil]; for (id object in bundleObjects) { if ([object isKindOfClass:[MyView class]]){ currView = (MyView *)object; break; } } [currView.myLabel setText:@"myText"]; [currView.myButton setTitle:@"myTitle" forState:UIControlStateNormal]; //... [currWrapperView addSubview:currView]; [myViews addObject:currView]; } //self.myViews = myViews; if need to access them later..

其他回答

@AVeryDev

6)将加载的视图附加到视图控制器的视图:

[self.view addSubview:myViewFromNib];

据推测,有必要将其从视图中删除以避免内存泄漏。

澄清一下:视图控制器有几个iboutlet,其中一些连接到原始nib文件中的项(像往常一样),一些连接到加载的nib中的项。两个nib都有相同的所有者类。加载的视图覆盖了原始视图。

提示:在加载的笔尖中设置主视图的不透明度为零,那么它将不会从原始笔尖中模糊项目。

这是一个很好的问题(+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,那将摇滚,但这让我在我需要的地方。

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

我也想做一些类似的事情,这是我发现的: (SDK 3.1.3)

我有一个视图控制器a(本身由一个导航控制器拥有),它在一个按钮按下加载VC B:

在AViewController.m

BViewController *bController = [[BViewController alloc] initWithNibName:@"Bnib" bundle:nil];
[self.navigationController pushViewController:bController animated:YES];
[bController release];

现在VC B有它的接口从Bnib,但当一个按钮被按下,我想去一个“编辑模式”有一个独立的UI从不同的nib,但我不想要一个新的VC的编辑模式,我想新的nib与我现有的B VC相关联。

在BViewController中。M(按按钮方式)

NSArray *nibObjects = [[NSBundle mainBundle] loadNibNamed:@"EditMode" owner:self options:nil];
UIView *theEditView = [nibObjects objectAtIndex:0];
self.editView = theEditView;
[self.view addSubview:theEditView];

然后按下另一个按钮(退出编辑模式):

[editView removeFromSuperview];

我又变回了原来的Bnib

这很好,但请注意我的EditMode。nib中只有一个顶级obj,一个UIView obj。 不管这个nib中的文件所有者是设置为BViewController还是默认的NSObject,但要确保文件所有者中的视图出口没有设置为任何东西。 如果是,那么我得到一个exc_bad_access崩溃,xcode继续加载6677个堆栈帧 显示一个内部UIView方法被反复调用…看起来像一个无限循环。 (视图出口是设置在我原来的Bnib然而)

希望这能有所帮助。

你也可以使用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文件来定位子视图的位置和大小。