20
votes

I have a project that is all in Objective C, except for my view controller, which is in Swift.

When I run it, i get the error

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[UIViewController _loadViewFromNibNamed:bundle:] loaded the "..." nib but the view outlet was not set.'

So I opened up my nib file, look at "File's Owner", and I see that the view does not even show up as an outlet at all.
For my old view controller (objective c), the view outlet does show up.

In my Swift view controller, I tried overriding the "view" variable from UIViewController in order to force it to be an @IBOutlet, but it complained about the "view" variable being of type UIView, complained about UIView?, and complained about UIView!.

Here are simplified versions of

my AppDelegate.h

#import <UIKit/UIKit.h>

@class MyViewController;
@class MyViewControllerSwift;

@interface MSAppDelegate : UIResponder <UIApplicationDelegate>
{
}

@property (strong, nonatomic) UIWindow *window;

@property (strong, nonatomic) UIViewController *viewController;

@end

AppDelegate.m

#import "MyAppDelegate.h"

#import "MyViewController.h"
#import "MySwift-Swift.h"
#import <UIKit/UIKit.h>

@implementation MyAppDelegate

static BOOL USE_SWIFT_VIEW_CONTROLLER = YES;

- (void)dealloc
{
    [_window release];
    [_viewController release];
    [super dealloc];
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    // Override point for customization after application launch.

    id viewControllerPtr = nil;
    if(USE_SWIFT_VIEW_CONTROLLER)
    {
        viewControllerPtr = [MyViewControllerSwift alloc];
    }
    else
    {
        viewControllerPtr = [MyViewController alloc];
    }

    UIViewController* vController = nil;
    if(USE_SWIFT_VIEW_CONTROLLER)
    {
        vController = [[viewControllerPtr initWithNibName:@"MyViewControllerSwift" bundle:nil] autorelease];
    }
    else
    {
        vController = [[viewControllerPtr initWithNibName:@"MyViewController" bundle:nil] autorelease];
    }

    self.viewController = vController;
    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];

    return YES;
}

ViewController.swift

import Foundation
import AVFoundation

@objc class MyViewControllerSwift : UIKit.UIViewController {

    var player : AVFoundation.AVAudioPlayer?;

    @IBOutlet weak var myTextView : UITextView!;

    required init(coder aDecoder : NSCoder) {
        super.init(coder:aDecoder);
    }

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName:nibNameOrNil, bundle:nibBundleOrNil);
    }

    override func viewDidLoad() {
        super.viewDidLoad();

        println("Using MyViewControllerSwift");
    }

    deinit {
        //TODO
    }
}

What do I need to do to get my view to display?

Thanks.

(Yes, this is a similar question to Loaded nib but the view outlet was not set - new to InterfaceBuilder but the view outlet does not show up. )

6

6 Answers

42
votes
  • First - set custom class in your nib file (File's Owner -> third icon -> custom class : YourViewController )
  • Second - the last icon in file's owner -> link (drag) the "view" property to the interface view

Init your ViewController like so:

YourViewController(nibName: "YourViewName", bundle: nil)

It will work. Don't do any manipulations with View.

13
votes

If you have tried everything and you still get this error, try re-creating the class file from scratch but remember to select the "Also create XIB file" check box. This will auto link up a few items that are not linked when creating these files separately. After this is created, you can likely cut and paste everything onto the new XIB and it should work fine.

I am finding this issue specifically with creating files separately in Swift.

1
votes

I had the same problem , my 2nd view on my view controller couldn't load . I changed the view's name in property(as I had previously given "View"). Your existing view controller already had references to the view on top of it with the same name(View). Hence the error . Try changing the outlet names . It worked perfect in my case .

1
votes

Originally I ran into this same issue when I had an empty .xib and dropped in a UIViewController.

My fix was to remove the UIViewController and just add a UIView instead. I made the File's Owner (under Placeholders) Custom Class -> Class the name of the UIViewController class that would contain all the controller logic. I connected the UIView in the .xib file to the view Placeholder -> File's owner -> Outlets.

Maybe Apple/Xcode is trying to enforce a more strict MVC design by removing the UIViewController from everything but storyboard? I tried to follow the advice of many other posts I saw in trying to connect my UIViewController's view (of the UIViewController I originally dropped into the .xib) but it wouldn't connect no matter whether I made the Class type in File's Owner or for the UIViewController the same as my custom class.

This is the only thing that worked for me in Xcode 11.0

0
votes

I found on chinese forum that it could be happen when you have similar names for ViewController and view from XIB.

Example SpecialOfferViewController and SpecialOfferView

I renamed

SpecialOfferViewController and OfferView and error has gone!!!

0
votes

I had a xib file named FooView and a view controller class named FooViewController.

FooVew was not intended to the be the root view of FooViewController, only a subview. Yet, UIViewController's default behavior is to automatically attempt exactly that. And thus, my app would crash with this error at the first point that my controller's view was accessed.

This behavior can be avoided using one of:

  1. Rename your controller class or the xib file to dissociate them
  2. override var nibName: String? { nil }
  3. override func loadView() and assign to view yourself

I went with 2 as it seemed the least likely sneak back to bite me later.