0

Here's the code:

import Cocoa

class MyWindowController: NSWindowController {

    var name: String

    override init(window: NSWindow?) {
        name = "Sue"
        super.init(window: window)
    }

    required init?(coder: NSCoder) {
        name = "Dave"
        super.init(coder: coder)
    }
}

let controller = MyWindowController()
println("A boy named \(controller.name).")  //=> "A boy named Sue."

Things I think I know:

  1. MainWindowController is not provided a no arg default init() because MainWindowController declares a property without a default value.

  2. NSWindowController does not have a no-arg init().

  3. NSObject does have a no arg init().

How does the overridden designated initializer init(window: NSWindow?) in MainWindowController get called?

@Arkku,

Just to be clear, NSWindowController's convenience init() would have to be implemented like this:

override convenience init() {
    self.init(window: nil)
}

Merely inheriting init() from NSObject will not do that.

7stud
  • 46,922
  • 14
  • 101
  • 127

1 Answers1

2

Since you are providing implementations for all of the designated initializers of the superclass NSWindowController, you are automatically inheriting the convenience initializers as well. It seems that the no-arg init() is one of these convenience initializers, calling the init(window:) with nil for window.

To clarify, assumption #2 (that NSWindowController doesn't have init()) is false; it does have such an init (just not currently listed in the class documentation). It is an Objective-C class for which the rules of Swift initializers do not apply, but when subclassing from the Swift side what matters is whether the method exists (which it does) and whether it is marked as a designated initializer (which it is not).

Arkku
  • 41,011
  • 10
  • 62
  • 84
  • That's what I think, however the docs do not list a no arg init() in NSWindowController. I also checked the .h file...no no arg init(). – 7stud Jul 21 '15 at 00:58
  • `NSWindowController` is a subclass of `NSObject`, which has `init()`. Cocoa docs do not duplicate every superclass's methods into the docs for every class. – Rob Napier Jul 21 '15 at 00:59
  • @RobNapier: Yes, see #3. How do you get from NSObject's init() to the overridden `init(window: NSWindow?)`? – 7stud Jul 21 '15 at 01:00
  • 1
    @7stud Even though the docs of `NSWindowController` do not specifically list `init()`, you can create an instance with `NSWindowController()`. Part of the reason why this is not so clearly documented might be due to the Objective-C roots of the method. – Arkku Jul 21 '15 at 01:04
  • @Arkku, It's not that simple. NSWindowController would have to override NSObjects init() in order to have it call the designated initializer in NSWindowController, i.e. `init(window: NSWindow?)` Therefore, the NSWindowController docs or the source code would have to list the overridden init(). – 7stud Jul 21 '15 at 01:16
  • Because `-[NSWindowController init]` calls `[NSWindowController initWithWindow:nil]`. That has always been true in Cocoa. Cocoa is implemented in ObjC, which does not have any of the initializer rules you're describing. – Rob Napier Jul 21 '15 at 01:17
  • It is worth opening radars (bugreport.apple.com) that the auto-generated header is somewhat misleading (though auto-complete is correct), but this shouldn't be surprising behavior for a Cocoa object. – Rob Napier Jul 21 '15 at 01:23
  • @RobNapier, *Because -[NSWindowController init] calls [NSWindowController initWithWindow:nil]* -- How do you know that? Is there source code I can look at? – 7stud Jul 21 '15 at 01:26
  • @7stud If `init()` was not a designated initializer in `NSWindowController` then you inherit it automatically by implementing all the designated initializers of `NSWindowController`, which appears to be happening here and thus we can infer that the superclass version was a convenience init (as far as Swift is concerned) which calls `init(window: nil)`. – Arkku Jul 21 '15 at 01:28
  • @Arkku: Yeah, I understand all that. But the problem is spelled out in my previous comment to you. A class can't inherit a method from NSObject and expect the method to magically interact with the class's other methods--the inherited method has to be overridden and implemented to do that. And therefore, the overridden implementation should appear in the docs and the .h file--yet there is nothing. Rob Napier knows what's going on with the source code in Objective-C, and I am curious how he knows that. Docs? Source Code? I can't find anything about it on the Objective-C side either. – 7stud Jul 21 '15 at 01:42
  • @7stud Well, the Objective-C version of `init` can be observed calling `initWithWindow:`, and in Objective-C the strict rules of Swift's explicit overrides, designated/convenience initializers, initializer inheritance, etc. do not apply, so basically any initializer (designated or not) from any superclass is typically overriden as it is also inherited by subclasses whether they want it or not. Apple may have omitted this `init()` from the docs either on purpose (as it is just an inconvenient inherited initializer that is not meant to be used) or due to a fault in the Obj-C -> Swift process. – Arkku Jul 21 '15 at 01:54
  • @7stud Note that some people just have their inherited `init` in Objective-C throw an exception to signal that it is not meant to be used, as there is no way to keep it from being inherited. Apple has made theirs more robust by providing an override which works with the new designated initializer, but they might still have preferred to not have the `init`… (See http://stackoverflow.com/questions/195078/is-it-possible-to-make-the-init-method-private-in-objective-c ) – Arkku Jul 21 '15 at 01:58