How to load a UIView using a nib file created with Interface Builder

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:

  • 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;
    }
    
  • 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.


    There is also an easier way to access the view instead of dealing with the nib as an array.

    1 ) Create a custom View subclass with any outlets that you want to have access to later. --MyView

    2 ) in the UIViewController that you want to load and handle the nib, create an IBOutlet property that will hold the loaded nib's view, for instance

    in MyViewController (a UIViewController subclass)

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

    (dont forget to synthesize it and release it in your .m file)

    3) open your nib (we'll call it 'myViewNib.xib') in IB, set you file's Owner to MyViewController

    4) now connect your file's Owner outlet myViewFromNib to the main view in the nib.

    5) Now in MyViewController, write the following line:

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

    Now as soon as you do that, calling your property "self.myViewFromNib" will give you access to the view from your nib!


    Thank you all. I did find a way to do what I wanted.

  • Create your UIView with the IBOutlet s you need.
  • Create the xib in IB, design it to you liking and link it like this: The File's Owner is of class UIViewController (No custom subclass, but the "real" one). The File Owner's view is connected to the main view and its class is declared as the one from step 1).
  • Connect your controls with the IBOutlet s.
  • The DynamicViewController can run its logic to decide what view/xib to load. Once its made the decission, in the loadView method put something like this:

    NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:@"QPickOneView"
                                                      owner:self
                                                    options:nil];
    
    QPickOneView* myView = [ nibViews objectAtIndex: 1];
    
    myView.question = question;
    
  • That's it!

    The main bundle's loadNibNamed method will take care of initializing the view and creating the connections.

    Now the ViewController can display a view or another depending on the data in memory, and the "parent" screen doesn't need to bother with this logic.


    I'm not sure what some of the answers are talking about, but I need to put this answer here for when I search in Google next time. Keywords: "How to load a UIView from a nib" or "How to load a UIView from an NSBundle."

    Here's the code almost 100% straight up from the Apress Beginning iPhone 3 book (page 247, "Using The New Table View Cell"):

    - (void)viewDidLoad {
        [super viewDidLoad];
        NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:@"Blah"
                                                     owner:self options:nil];
        Blah *blah;
        for (id object in bundle) {
            if ([object isKindOfClass:[Blah class]]) {
                blah = (Blah *)object;
                break;
            }
        }   
        assert(blah != nil && "blah can't be nil");
        [self.view addSubview: blah];
    } 
    

    This supposes you have a UIView subclass called Blah , a nib called Blah which contains a UIView which has its class set to Blah .


    Category: NSObject+LoadFromNib

    #import "NSObject+LoadFromNib.h"
    
    @implementation NSObject (LoadFromNib)
    
    + (id)loadFromNib:(NSString *)name classToLoad:(Class)classToLoad {
        NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:name owner:self options:nil];
        for (id object in bundle) {
            if ([object isKindOfClass:classToLoad]) {
                return object;
            }
        }
        return nil;
    }
    
    @end
    

    Swift Extension

    extension UIView {
        class func loadFromNib<T>(withName nibName: String) -> T? {
            let nib  = UINib.init(nibName: nibName, bundle: nil)
            let nibObjects = nib.instantiate(withOwner: nil, options: nil)
            for object in nibObjects {
                if let result = object as? T {
                    return result
                }
            }
            return nil
        }
    }
    

    And an example in use:

    class SomeView: UIView {
        class func loadFromNib() -> SomeView? {
            return self.loadFromNib(withName: "SomeView")
        }
    }
    
    链接地址: http://www.djcxy.com/p/78230.html

    上一篇: 带有UIView按钮的UIPageControl

    下一篇: 如何使用用Interface Builder创建的nib文件加载UIView