How to load a UIView using a nib file created with

2019-01-01 07:27发布

I'm trying to do something a bit elaborate, but something that should be possible. So here is a challenge for all you experts out there (this forum is a pack of a lot of you guys :) ).

I'm creating a Questionnaire "component", which I want to load on a NavigationContoller (my QuestionManagerViewController). The "component" is an "empty" UIViewController, which can load different views depending on the question that needs to be answered.

The way I'm doing it is:

  1. Create Question1View object as a UIView subclass, defining some IBOutlets.
  2. 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.
  3. I link the outlets with the view's component (using IB).
  4. 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;
    }
    

When I run the code, I'm getting this error:

2009-05-14 15:05:37.152 iMobiDines[17148:20b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[UIViewController _loadViewFromNibNamed:bundle:] loaded the "Question1View" nib but the view outlet was not set.'

I'm sure there is a way to load the view using the nib file, without needing to create a viewController class.

24条回答
残风、尘缘若梦
2楼-- · 2019-01-01 08:11

After spending many hours, I forged out following solution. Follow these steps to create custom UIView.

1) Create class myCustomView inherited from UIView.
enter image description here

2) Create .xib with name myCustomView.
enter image description here

3) Change Class of UIView inside your .xib file, assign myCustomView Class there.
enter image description here

4) Create IBOutlets
enter image description here

5) Load .xib in myCustomView * customView. Use following sample code.

myCustomView * myView = [[[NSBundle mainBundle] loadNibNamed:@"myCustomView" owner:self options:nil] objectAtIndex:0];
[myView.description setText:@"description"];

Note: For those who still face issue can comment, I will provide them link of sample project with myCustomView

查看更多
初与友歌
3楼-- · 2019-01-01 08:12

I ended up adding a category to UIView for this:

 #import "UIViewNibLoading.h"

 @implementation UIView (UIViewNibLoading)

 + (id) loadNibNamed:(NSString *) nibName {
    return [UIView loadNibNamed:nibName fromBundle:[NSBundle mainBundle] retainingObjectWithTag:1];
 }

 + (id) loadNibNamed:(NSString *) nibName fromBundle:(NSBundle *) bundle retainingObjectWithTag:(NSUInteger) tag {
    NSArray * nib = [bundle loadNibNamed:nibName owner:nil options:nil];
    if(!nib) return nil;
    UIView * target = nil;
    for(UIView * view in nib) {
        if(view.tag == tag) {
            target = [view retain];
            break;
        }
    }
    if(target && [target respondsToSelector:@selector(viewDidLoad)]) {
        [target performSelector:@selector(viewDidLoad)];
    }
    return [target autorelease];
 }

 @end

explanation here: viewcontroller is less view loading in ios&mac

查看更多
一个人的天荒地老
4楼-- · 2019-01-01 08:15

This is something that ought to be easier. I ended up extending UIViewController and adding a loadNib:inPlaceholder: selector. Now I can say

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

Here's the code for the category (it does the same rigamarole as described by 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
查看更多
浮光初槿花落
5楼-- · 2019-01-01 08:18

In swift

Actually my resolution to this problem was, to load the view in a viewDidLoad in my CustonViewController where I wanted to use the view like that:

myAccessoryView = NSBundle.mainBundle().loadNibNamed("MyAccessoryView", owner: self, options: nil)[0] as! MyAccessoryView

Don't load the view in a loadView() method! The loadView method serves for loading the view for your custom ViewController.

查看更多
孤独寂梦人
6楼-- · 2019-01-01 08:19

The previous answer does not take into account a change in the NIB (XIB) structure that occurred between 2.0 and 2.1 of the iPhone SDK. User contents now start at index 0 instead of 1.

You can use the 2.1 macro which is valid for all version 2.1 and above (that's two underscores before 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;

We use a technique similar to this for most of our applications.

Barney

查看更多
萌妹纸的霸气范
7楼-- · 2019-01-01 08:20

None of the answers explain how to create the stand alone XIB that is the root of this question. There is no Xcode 4 option to "Create New XIB File".

To do this

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

This may seem simple but it can save you a few minutes poking around for it since the word "XIB" does not appear anywhere.

查看更多
登录 后发表回答