If I declare
public class A: NSObject {
public class X { }
public init?(x: X? = nil) { }
}
all is fine. When using it like let a = A(), the initializer is called as expected.
Now, I'd like to have the nested class X private, and the parameterized init as well (has to be, of course). But a simple init?() should stay publicly available as it was before. So I write
public class B: NSObject {
private class X { }
private init?(x: X?) { }
public convenience override init?() { self.init(x: nil) }
}
But this gives an error with the init?() initializer: failable initializer 'init()' cannot override a non-failable initializer with the overridden initializer being the public init() in NSObject.
How comes I can effectively declare an initializer A.init?() without the conflict but not B.init?()?
Bonus question: Why am I not allowed to override a non-failable initializer with a failable one? The opposite is legal: I can override a failable initializer with a non-failable, which requires using a forced super.init()! and thus introduces the risk of a runtime error. To me, letting the subclass have the failable initializer feels more sensible since an extension of functionality introduces more chance of failure. But maybe I am missing something here – explanation greatly appreciated.
After a bit of fiddling I think I understand. Let's consider a protocol requiring this initializer and a class implementing it:
This gives the error: "Initializer requirement 'init()' can only be satisfied by a
requiredinitializer in non-final class 'A'". This makes sense, as you could always declare a subclass ofAthat doesn't inherit that initializer:So we need to make our initializer in
Arequired:Now if we look at the
NSObjectinterface we can see that the initializer is notrequired:We can confirm this by subclassing it, adding a different initializer and trying to use the normal one:
Now here comes the weird thing: We can extend
NSObjectto conform to theIprotocol, even though it doesn't require this initializer:I honestly think this is either a bug or a requirement for ObjC interop to work (EDIT: It's a bug and already fixed in the latest version). This error shouldn't be possible:
Now to answer your actual question:
In your second code sample, the compiler is right in that you cannot override a non-failable with a failable initializer.
In the first one, you aren't actually overriding the initializer (no
overridekeyword either), but instead declaring a new one by which the other one can't be inherited.Now that I wrote this much I'm not even sure what the first part of my answer has to do with your question, but it's nice to find a bug anyways.
I suggest you to do this instead:
Also have a look at the
Initializationsection of the Swift reference.