Adding Convenience Initializers in Swift Subclass
My understanding of Initializer Inheritance is the same as yours, and I think we are both well aligned with what the book states. I don't think it's an interpretation issue or a misunderstanding of the stated rules. That said, I don't think you're doing anything wrong.
I tested the following in a Playground and it works as expected:
class RectShape: NSObject {
var size = CGSize(width: 0, height: 0)
convenience init(rectOfSize size: CGSize) {
self.init()
self.size = size
}
}
class SquareShape: RectShape {
convenience init(squareOfSize size: CGFloat) {
self.init(rectOfSize: CGSize(width: size, height: size))
}
}
RectShape
inherits from NSObject
and doesn't define any designated initializers. Thus, as per Rule 1, it inherits all of NSObject
's designated initializers. The convenience initializer I provided in the implementation correctly delegates to a designated initializer, prior to doing the setup for the intance.
SquareShape
inherits from RectShape
, doesn't provide a designated initializer and, again, as per Rule 1, inherits all of SquareShape
's designated initializers. As per Rule 2, it also inherits the convenience initializer defined in RectShape
. Finally, the convenience initializer defined in SquareShape
properly delegates across to the inherited convenience initializer, which in turn delegates to the inherited designated initializer.
So, given the fact you're doing nothing wrong and that my example works as expected, I am extrapolating the following hypothesis:
Since SKShapeNode
is written in Objective-C, the rule which states that "every convenience initializer must call another initializer from the same class" is not enforced by the language. So, maybe the convenience initializer for SKShapeNode
doesn't actually call a designated initializer. Hence, even though the subclass MyShapeNode
inherits the convenience initializers as expected, they don't properly delegate to the inherited designated initializer.
But, again, it's only a hypothesis. All I can confirm is that the mechanics works as expected on the two classes I created myself.
Designation & Convenience Initializer
Since you have two designated initializers in A
, these are non-ambiguous due to different signatures, and can be differentiated from each other. This means you can readily call the appropriate designated initializer of A
from the subclass B
. E.g., for A
as
class A {
var a: Int
// designated "#1"
init() {
a = 0
}
// designated "#2"
init(_ a: Int) {
self.a = a
}
// convenience initializer for A
convenience init(_ foo: String) {
print(foo)
self.init(42)
}
}
We have, e.g.
class B: A {
let b: Int
// designated "sub#1"
override init() {
b = 42
super.init() // use A's designated #1
}
// designated "sub#2"
override init(_ a: Int) {
b = 24
super.init(a) // use A's designated #2
}
// non-overriding designated "#3"
init(b: Int) {
self.b = b
super.init() // use A's designated #1
}
// convenience initializer for B
convenience init(_ foo: String) {
print(foo)
self.init() // use B's designated #1
}
// you may only call designated initializers of the superclass
}
Note however that the initializers of a subclass may only call designated initializers of its superclass. This is covered by rules 1 and 2 in the Language Guide - Initializers - Initializer Delegation for Class Types [emphasis mine]:
Initializer Delegation for Class Types
To simplify the relationships between designated and convenience
initializers, Swift applies the following three rules for delegation
calls between initializers:Rule 1
A designated initializer must call a designated initializer from its
immediate superclass.Rule 2
A convenience initializer must call another initializer from the same
class.Rule 3
A convenience initializer must ultimately call a designated
initializer.
So you may not access the convenience initializers of A
from the convenience initializers of B
, and the designated initializers of B
must naturally, by rule 1 above, call only the designated initializers of A
.
Swift - Convenience initializer in subclass of CIDetector is not working
Swift imports some class methods as convenience initializers (Class Factory Methods and Convenience Initializers).
In your case, init(ofType:context:options:)
is a class method of CIDetector
in Objective-C + detectorOfType:context:options:
.
Such convenience initializers are not available in subclasses. It's a natural conclusion based on the fact that such factory method of a class always creates an instance of the class, it cannot create an instance of the subclass you defined.
So, if you want to provide another convenience initializer utilizing a convenience initializer based on Class Factory Method, you may need an extension.
extension CIDetector {
convenience init?(rectDetectorWithAspectRatio aspectRatio: Float) {
let options: [String : Any] = [CIDetectorAccuracy : CIDetectorAccuracyHigh,
CIDetectorAspectRatio : NSNumber(value: aspectRatio)]
self.init(ofType: CIDetectorTypeRectangle, context: nil, options: options)
}
}
By the way, the diagnostics messages are seemingly completely broken from the programmers' side using Swift. You can send a Bug Report about it.
Create convenience Initializer on subclass that calls failable Initializer
The initialiser delegation rule #2 states
A convenience initializer must call another initializer from the same
class.
Your class doesn't define init?(named:String), so it will call superclass initialiser (which you do have access to under the other rule #2 you were referring to), but this won't satisfy the requirement to call a non-convenience initialiser from your class.
You can simply call self.init
before calling the superclass initialiser.
convenience init? (i:UIViewController){
self.init()
self.init(named:"")
}
Related Topics
How to Get the Height and Width of an Uiimage
How to Implement a Swiping/Sliding Animation Between Views
Open Link to Facebook Page from iOS App
Silent Push Notifications Only Delivered If Device Is Charging And/Or App Is Foreground
Fetching All Contacts in iOS Swift
Uitextview Style Is Being Reset After Setting Text Property
Scale Image in an Uibutton to Aspectfit
Swift: How to Get Substring from Start to Last Index of Character
What Tool(S) How to Use to Produce iPhone App Screencasts
Make Custom Button on Tab Bar Rounded
Proper Use of Loadview and Viewdidload with Uiviewcontroller Without Nibs/Xibs
How to Print Core Data Debug Values
How to Programmatically Increase Uitableview Cell's Height in Iphone