Subclassing a class that has convenience initializers.

Hi all.


Note: I am using the latest version of Xcode and Swift to date (official releases.)


Here is a scenario. ClassA (a framework class) defines a convenience initializer. Subclass ClassB (my custom class) defines a new optional property and a designated initializer for it. (As per the Swift Programming Language 2.1, defining an initializer for the subclass means that none of the superclass's initializers will be inherited.)


Now, what I want to be able to do is create an instance of ClassB using the convenience initializer from ClassA. Is this possible? If so, how?

I cannot override the convenience initializer because, being a framework class, I don't know what it does. And I can't call a convenience initializer from a superclass as per the rules of the language.


class BaseClass {
  var property1 = 0

  init(property1: Int) {
    self.property1 = property1
  }

  convenience init(value1: Int, value2: Int) {
    // Super secret formula hidden in a frame work that I don't have access to.
    self.init(property1: value1 + value2)
  }
}

class SubClass: BaseClass {
  var property2: Int?

  init(property2: Int) {
    super.init(property1: 10)
    self.property2 = property2
  }
}

let c1 = SubClass(property2: 4)
print(c1.property2!)

// This part won't compile.  What can be done to get this to work?
let c2 = SubClass(value1: 5, value2: 5)
print(c2.property1)


For a real-world scenario, try subclassing SpriteKit's SKScene and provide at least 1 custom initializer and then try to create an instance of your SKScene subclass using the fileNamed: initializer. When I try, ultimately I get an "Incorrect argument label in call (have 'fileNamed:', expected 'coder:')" as I cannot figure out how to implement fileNamed: in my subclass. Funny thing is, fileNamed: is a convenience initializer defined up the chain in SKNode and SKScene does define its own initializer init(size: CGSize). Unless I'm mistaken, SKScene is a class that successfully does what I am looking to do (because you can create an instance of SKScene using fileNamed:) How to extend that ability to my custom SKScene subclass is a mystery to me.


Any help would be appreciated. Thanks.

Accepted Answer

If you override all of the superclass designated initializers, you'll inherit the superclass convenience initializers. (See Swift docs, "Initialization" -> "Automatic Initializer Inheritance" -> "Rule 2".) I think in this case that means you can define an init(property1:) that just calls through to super and you should able to use init(value1:value2) for subclass initialization.

Answers

If you override all of the superclass designated initializers, you'll inherit the superclass convenience initializers. (See Swift docs, "Initialization" -> "Automatic Initializer Inheritance" -> "Rule 2".) I think in this case that means you can define an init(property1:) that just calls through to super and you should able to use init(value1:value2) for subclass initialization.

You are indeed correct, sir. Thank you.


For those interested in subclassing SKScene (with added initializers), this means overriding init() and init(size: CGSize).


Edit: SKScene's required init?(coder aDecoder: NSCoder) will also need to be implemented.

Sometimes it's the little things we don't remember or take notice of that haunt us for hours. I was about to rethink my whole life because of this little devil in the detail. This allows me to finally get a working SKScene without having to do an awful lot of node copies. Thank you.