unimplemented initializer error makes no sense

Hi,

Can anyone help me understand this error? I subclass UITableViewController, as show below. The error is:

fatal error: use of unimplemented initializer 'init(nibName:bundle:)' for class 'MyApp.MyViewController'

class MyViewController: UITableViewController {
    var thing: Thing

    init(thing: Thing) {
        self.thing = thing
        super.init(style: .Grouped)
    }


It then requires me (why I don't know) to add this:


required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}


Then it compiles fine. My code calls `init(thing:)` and it crashes with that error.


Rob

Xcode 7b6

This is a known problem. There is a workaround but it may have some downsides. Just try it & check the result:

http://stackoverflow.com/a/30328763/1183577

That stackoverflow question was about setting properties before calling super.init. That's expected behavior, and obviously not my problem here. Are you saying there is some magic internal Swift bug that requires I call up to init(nibName:...) here? If so, wow, that's bad. Is that discussed anywhere else, like in this forum? Has it been reported to Apple?


If that's the workaround I can't use it because I need to set the style with init(style:) I'll go back to creating the controller in interface builder.


Rob

Your issue cannot be reproduced in my Xcode 7 beta 6.


With initializing MyViewController with `init(thing:)`, I can get the newly created instance of MyViewController and no fatal error occurs.

        let vc = MyViewController(thing: Thing())
        print(vc) //-><MySubclassTableVC.MyViewController: 0x7f8d195f1750>


Are there something calling 'init(nibName:bundle:)' hidden in your project?

In XCode 7 beta 6 I didn't get this error. But I was required to implement `init?(coder aDecoder: NSCoder)` even though the initializer exists in the superclass. This code compiles (and you could alternatively also call `super.init(coder: aDecoder)` if you have a default for `thing`):


import UIKit
class MyViewController: UITableViewController {
  var thing: Int
  init(thing: Int) {
    self.thing = thing
    super.init(style: .Grouped)
  }
  required init?(coder aDecoder: NSCoder) {
    fatalError()
  }
}


For XCode 6, what you report seems to be a known problem with a discussion and some proposed solutions here:

http://stackoverflow.com/questions/25139494/how-to-subclass-uitableviewcontroller-in-swift

(check out the code of the first answer)

The stack trace at shows init(withNib:...) is being called by init(style:)


I did simplify my posted code, and I'm not sure what the relevant difference is. Maybe because I'm building for iOS 8 and running 8.4 iPad? Did you test on 9.0?


My workaround now is to delete my implementations of init(thing:) and init(coder:) and make `thing` a Thing! so I can set it after creating the object. That runs fine.


Rob

Thanks for that link. Did you test this in iOS 9. I'm deploying to iOS 8, so I'm curious if that's the difference. If so, scary...

Isn't this the case also for eg UIView, NSView (in OS X), and really anything that conforms to NSCoding:

public protocol NSCoding {
  
    public func encodeWithCoder(aCoder: NSCoder)
    public init?(coder aDecoder: NSCoder) // NS_DESIGNATED_INITIALIZER
}

?

Maybe because I'm building for iOS 8 and running 8.4 iPad? Did you test on 9.0?

That's it. I could reproduce your issue with iOS 8.4 sim. Sorry for having missed such basic settings.


Another work around is to make your init(thing:) a convenience initializer. (You need to make `thing` as Thing! in this case as well.)

class MyViewController: UITableViewController {
    var thing: Thing!

    convenience init(thing: Thing) {
        self.init(style: .Grouped)
        self.thing = thing
    }

    //No designated init cannot appear...
}

While adding only convenience initializers, your class can inherit all designated initializers including init(nibName:bundle:) .

I didn't mean to talk about the init(coder:) requirement. I'm talking about the error in my original post -- a runtime crash about missing init(nibName:bundle:).

That stackoverflow question was about setting properties before calling super.init. That's expected behavior, and obviously not my problem here. Are you saying there is some magic internal Swift bug that requires I call up to init(nibName:...) here? If so, wow, that's bad.


The StackOverflow question is about the same issue:

init(nibName:bundle:)
in
UITableViewController
.


init(style:)
of
UITableViewController
calls
init(nibName:bundle:)
on
self
instead of
super
internally.

This causes

init(nibName:bundle:)
to be called in YOUR subclass. Since this initializer isn't implemented it will fail at runtime. Nor does Swift support that more than one designated initializer is called, which would lead to even weirder behavior.

In Objective-C that behavior was already a bit broken. Now Swift is much stricter and doesn't support the broken initializer mess and it took Apple until iOS 9 to fix this issue.


So there is no simple way to call

init(style:)
from a subclass.


What you could try is to create the

UITableView
manually. Overwrite
loadView()
and set
self.view
to a new
UITableView
created with the style you want. Just don't forget to set its
dataSource
and
delegate
to
self
.
unimplemented initializer error makes no sense
 
 
Q