24

I've read Using XCode storyboard to instantiate view controller that uses XIB for its design but I'm having troubles making this work in Swift (Using Xcode 6 Beta 6). I'm wondering if I've done something wrong or if this functionality isn't available anymore?

I created a simple repository, https://github.com/jer-k/StoryboardTesting-Swift, that showcases the above approach.

I managed to solve the issue by adding and override to init

required init(coder aDecoder: NSCoder) {
    super.init(nibName: "TestViewController", bundle: NSBundle.mainBundle())
}

but I'm wondering if it is still possible to have the storyboard handle this for me. Creating a superclass to have all my UIViewControllers inherit from with the above code isn't the most cumbersome thing in the world, but I'm just curious at this point.

Community
  • 1
  • 1
jer-k
  • 1,413
  • 2
  • 12
  • 23

2 Answers2

41

What's happened is that Seed 5 broke the mechanism whereby a view controller can find its xib by name, if the view controller is a Swift class. The reason is that the name of the class, in Swift's mind, is not the same as the name you gave it (and the name you gave the xib file); the name has been "mangled", in particular by prepending the module name (i.e. Swift classes have namespacing).

I offer three workarounds:

  • Your workaround is a good one (load the .xib file by name explicitly)

  • Name the .xib file MyModule.TestViewController.xib, where MyModule is the name of your bundle (i.e. the name of the project) (this is what Apple advises, but I hate it)

  • Use @objc(TestViewController) before the view controller's class declaration to overcome the name mangling which is what's breaking the mechanism (this is the approach I favor)

See my discussion here: https://stackoverflow.com/a/25163757/341994 and my further discussion linked to from there: https://stackoverflow.com/a/25152545/341994

EDIT This bug is fixed in iOS 9 beta 4. If the nib file search fails, iOS 9 now strips the module name off the view controller class name and performs the nib file search a second time.

Community
  • 1
  • 1
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • I have some slight hope that Apple will respond to my bug reports by fixing this, but the fact that they closed my bug with "works as intended" is discouraging. – matt Aug 28 '14 at 00:39
  • I see your discussion the second linked answer and I understand. Was it ever documented that we needed to start prepending the module name onto xibs? Maybe I missed it. Either way, awesome work. I'm going to use the @objc approach for now because it will be very easy to remove if they decide to drop the need for the prepended module name. If we come out of beta and it is finalized that we have to prepend the module name I may switch since it is their advised approach, but now I like your solution. – jer-k Aug 28 '14 at 00:45
  • 1
    A caveat to add: I had to go back into the Storyboard and reset the name to pick up the un-mangled version, but it works like a charm. – jer-k Aug 28 '14 at 00:59
  • "Was it ever documented that we needed to start prepending the module name onto xibs" No, it's just something Apple told me directly... – matt Aug 28 '14 at 01:06
  • the @objc(testViewController) approach doesn't work for me... apparently it has a "compiler error: Expected declaration". – S.H. Sep 17 '14 at 20:16
  • 1
    @StevenHernandez Then you're doing it wrong. I do this all the time. See for example https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/bk2ch06p239nibViewControllerWorkaround4/ch19p575manualViewController/RootViewController.swift – matt Sep 17 '14 at 22:13
  • AHH see now thats a better example of how to use it. With your first example I assumed incorrectly that I could just copy paste that sstatement anywhere inside the Class declaration of the ViewController.. Thanks for the help +1 – S.H. Sep 18 '14 at 02:15
  • These are not working for me. Maybe because I am loading a xib from a framework into my storyboard. – xissburg Feb 03 '15 at 18:58
  • @xissburg What does "into my storyboard" mean? You can't load a _.xib_ "into a storyboard" in any way that I can make sense of. – matt Feb 03 '15 at 19:08
  • I mean what the OP said. To load a view controller from a xib in a storyboard. I got it working now but only the OP's suggestion works. – xissburg Feb 03 '15 at 19:12
  • @xissburg I'm now (mentally) with you... Interesting stuff. Your issue might make a good separate question, because you're doing something different (because of the framework) - and then you could answer your own question and solve this for others. Just an idea, if you have time. – matt Feb 04 '15 at 01:41
  • Sometimes, and I don't know how this happens but IB will create this issue again and again, IB will not leave the module blank for some random Objective-C classes. In that case, hacking the storyboard works. This happened to some guy -- http://stackoverflow.com/a/40719723/8047 - and also to me (another guy). – Dan Rosenstark Jan 10 '17 at 23:56
  • 1
    Had to manually remove this from the storyboard: `customModule="xxxx" customModuleProvider="target"`even though everything is in all targets.This only happens to me with one particular storyboard: not sure what makes it special. – Dan Rosenstark Jan 11 '17 at 00:08
  • @matt Are the proposed fixes still working in XCode 9.1? I've tried them all and none work for me. ViewController is not loaded in the Storyboard, although it loads in the runtime, e.g. when I run the app in the simulator. – Srđan Stanić Nov 10 '17 at 16:04
  • @SrđanStanić The "fixes" have not been needed for several years. It sounds like you're having some other problem. I suggest you ask about it as a real question, giving actual details (and blip me if you want me to take a look). – matt Nov 10 '17 at 16:24
  • @matt Thanks for your reply. Before I create a new question, I just want to make sure that it's a different issue. I've downloaded the repo from here https://github.com/jer-k/StoryboardTesting-Swift and in the main storyboard I would expect to see "Am I working" but instead I'm seeing grey Test View Controller, which means that its view did not load from the nib file. Is your experience or expectation different? – Srđan Stanić Nov 10 '17 at 18:17
  • That repo uses such an old version of Swift that I can't even open it. Instead of living in the past, try it yourself with a new project. – matt Nov 10 '17 at 18:27
  • @matt Here is a new question if you want to take a look. I appreciate your assistance so far. https://stackoverflow.com/questions/47229338/uiviewcontroller-defined-in-a-xib-file-doesnt-load-in-the-storyboard – Srđan Stanić Nov 10 '17 at 18:52
  • @SrđanStanić So it turns out that your question has nothing to do with what I'm talking about here (or very little to do with it). You are seeing correct and expected behavior. – matt Nov 10 '17 at 19:15
2

Another answer is:

override func loadView() {
    if #available(iOS 9, *) {
        super.loadView()
    } else {
        let classString = String(self.dynamicType)
        NSBundle.mainBundle().loadNibNamed(classString, owner: self, options: nil)
    }
}

link: http://japko.net/2014/09/08/loading-swift-uiviewcontroller-from-xib-in-storyboard/

EDIT:

override var nibName: String? {
    get {
        let classString = String(self.dynamicType)
        return classString
    }
}
override var nibBundle: NSBundle? {
    get {
        return NSBundle.mainBundle()
    }
}

This looks more beautiful. Works on iOS 8/9 (maybe on iOS 7 too, who knows...))

Dmitrii Cooler
  • 4,032
  • 1
  • 22
  • 21