What's the Difference Between a Required Initializer and a Designated Initializer

What's the difference between a required initializer and a designated initializer?

Required initialisers and designated initialisers are not really related, though the associated keywords required and convenience are both used to specify restrictions on subclasses.

Required Initialisers

A required initialiser makes a guarantee that you can initialise a type, or any of its sub-types, with that initialiser. If you have an initialiser in a protocol and you conform something to that protocol, you have to use required (if it's a class) because that protocol guarantees that the initialiser is present on that class, and any of its subclasses. When you use required on an initialiser of a class, that signals that all of its subclasses can also be initialised using that method. This means you also need to add that initialiser to any of its subclasses.

protocol TestProtocol {
init()
}

class TestClass: TestProtocol {
required init() {

}
}

Here, the required keyword must be present because any subclasses of TestClass must also provide init() (because they also conform to TestProtocol).

Having a required initialiser allows you to initialise a class without knowing what it is at compile time, which is useful for a variety of reasons:

let classType: TestProtocol.Type = TestClass.self
let object = classType.init()

If your class conformed to multiple protocols, each with a different initialiser for example, each of those initialisers must also be required:

protocol OtherProtocol {
init(thing: Int)
}

class OtherClass: TestClass, OtherProtocol {
let thing: Int

required init() { // Required from superclass/its protocol
self.thing = 0
}

required init(thing: Int) { // Required from new protocol
self.thing = thing
}
}

Note that adding super.init() isn't required in this special case, because Swift will automatically include the call if it takes no parameters.

In all the above examples, the initialisers are designated because they do not include the convenience keyword.

Even if you didn't have any protocols, you can still make use of required by initialising a type of a class which isn't known at compile time:

class BaseClass {
let value: Int

required init(value: Int) {
self.value = value
}
}

class SubClass: BaseClass {
required init(value: Int) { // Required from superclass
super.init(value: value) // Must call desginated initialiser of superclass
}
}

let someBaseClassType: BaseClass.Type = SubClass.self
let someBaseClassInstance = someBaseClassType.init(value: 1)

Designated Initialisers

A designated initialiser is one which isn't a convenience initialiser (i.e, marked with convenience). A designated initialiser must make sure that all properties of the class have a value before the initialiser finishes (or a super initialiser is called). Convenience initialisers only don't have this requirement because they must themselves call a designated initialiser.

class OtherSubClass: BaseClass {
convenience required init(value: Int) {
self.init() // Must call designated initialiser of this class
}

init() {
super.init(value: 0) // Must call designated initialiser of superclass
}
}

(This is fairly contrived example.)

In my experience, convenience initialisers are rarely useful and I tend to find the problems they solve can be solved using optional arguments on designated initialisers instead. One also needs to consider the fact that initialisers can't call convenience initialisers on their superclass, so make sure you don't have any convenience initialisers which provide functionality that your designated initialisers don't if you intend your class to be subclassed!


Structs and enums don't use the required or convenience keywords because these keywords are both used to indicate initialisation rules for subclasses, which only classes support: The required keyword indicates that subclasses must provide that initialiser, and the convenience keyword indicates that subclasses cannot call that initialiser. Despite not having the keywords, they must still provide initialisers defined in any protocols they conform to, and you can write 'convenient' initialisers which call self.init, just without the convenience keyword.


To respond to your statements:

  • Required initialisers don't have to be designated.
  • Designated initialisers don't have to be required.
  • Classes can have multiple required and designated initialisers.

What is the difference between convenience init vs init in swift, explicit examples better

Standard init:

Designated initializers are the primary initializers for a class. A
designated initializer fully initializes all properties introduced by
that class and calls an appropriate superclass initializer to continue
the initialization process up the superclass chain.

convenience init:

Convenience initializers are secondary, supporting initializers for a
class. You can define a convenience initializer to call a designated
initializer from the same class as the convenience initializer with some
of the designated initializer’s parameters set to default values. You can
also define a convenience initializer to create an instance of that class
for a specific use case or input value type.

per the Swift Documentation

In a nutshell, this means that you can use a convenience initializer to make calling a designated initializer faster and more "convenient". So convenience initializers require the use of self.init instead of the super.init you might see in an override of a designated initializer.

pseudocode example:

init(param1, param2, param3, ... , paramN) {
// code
}

// can call this initializer and only enter one parameter,
// set the rest as defaults
convenience init(myParamN) {
self.init(defaultParam1, defaultParam2, defaultParam3, ... , myParamN)
}

I use these a lot when creating custom views and such that have long initializers with mainly defaults. The docs do a better job explaining than I can, check them out!

Swift - A little confusion between Required Initializer vs. Delegating initializer

A required initializer means that every subclass must also implement the same initializer. Since you made the init(_:) initializer required in the Dog class, every subclass (and their subclasses) of Dog must also provide the same required init(_:) initializer.

From the looks of things, you don't need to make the init(_:) initializer in the Dog class required. Remove that keyword and then you can remove the init(_:) initializer from the NewDog class.

Bonus - both init methods in your NewDog class are designated initializers since neither is a convenience initializer.

You need to learn the differences and uses of default, convenience, and required initializers. This is all clearly covered in the Intializers section of The Swift Programming Language book.

difference between override init and required init? - swift

override init(frame: CGRect) is used when you create the view (in this case the button) programmatically.

required init?(coder: NSCoder) is used when the view is created from storyboard/xib.

since the latter is required you must implement its body. However if you are not going to create the button manually the first one is not required and can be omitted

setup is called in both because however you choose to create the button you want to setup its custom behavior so it will work as you intended it to

Why use required Initializers in Swift classes?

It's actually just a way of satisfying the compiler to assure it that if this class were to have any subclasses, they would inherit or implement this same initializer. There is doubt on this point, because of the rule that if a subclass has a designated initializer of its own, no initializers from the superclass are inherited. Thus it is possible for a superclass to have an initializer and the subclass not to have it. required overcomes that possibility.

One situation where the compiler needs to be satisfied in this way involves protocols, and works like this:

protocol Flier {
init()
}
class Bird: Flier {
init() {} // compile error
}

The problem is that if Bird had a subclass, that subclass would have to implement or inherit init, and you have not guaranteed that. Marking Bird's init as required does guarantee it.

Alternatively, you could mark Bird as final, thus guaranteeing the converse, namely that it will never have a subclass.

Another situation is where you have a factory method that can make a class or its subclass by calling the same initializer:

class Dog {
var name: String
init(name: String) {
self.name = name
}
}

class NoisyDog: Dog {

}

func dogMakerAndNamer(whattype: Dog.Type) -> Dog {
let d = whattype.init(name: "Fido") // compile error
return d
}

dogMakerAndNamer is calling the init(name:) initializer on Dog or a Dog subclass. But how can the compiler be sure that a subclass will have an init(name:) initializer? The required designation calms the compiler's fears.

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.

Designated Initializer, clarify please.

In Objective-C, the designated initializer of a class is the method that's responsible for properly initializing the class to put it in an appropriate state for use. There is nothing in the code that marks it as the designated initializer, so there is usually a comment in the header file for that. It is up to the developer who is using or extending that class to figure out which method is the designated initializer (usually init or prefixed with init) and to write code accordingly. This can lead to mis-use of a class if it is not properly documented and its source code is not available and is one of the shortcomings that Swift attempts to solve. So to address your questions...

  1. A designated initializer is not determined by the compiler. A subclass should also have a designated initializer that calls the super's designated initializer at some point.
  2. Each class should clearly state (via comments or documentation) which initializer is intended to be used as the designated initializer. It is up to the developer who is using the class to make sure that the designated initializer is invoked. It is up to the developer of the class itself to ensure that the super's designated initializer is invoked as intended. However, with properly written classes, any of the init methods should invoke the designated initializer. However, it is not guaranteed by the compiler.
  3. Other init methods need to be coded appropriately to invoke the designated initializer via [self init...] or [super init...]. Again, it is up to you to figure out how a class is intended to be used and to use it or extend it appropriately.

The designated initializer is the method that does the "heavy lifting" to prepare a new instance of a class for use. Other initializers are known as convenience initializers and are typically used to provide shorter signatures with implied defaults since you can't specify default parameter values for Objective-C method signatures.

In most cases, if a class is properly written, you shouldn't really have to worry too much since all convenience initializers should end up invoking the designated one.

A lot of thought was put into this during the development of Swift and even if you don't intend to learn it, you should read up on Swift Initializers as it will give you good insight into the proper chain of initialization that you could then use to guide you in creating initializers in Objective-C.

UPDATE:
Since Xcode 6, designated initializers can be marked as such, typically via the NS_DESIGNATED_INITIALIZER macro. This helps enforce properly written classes and is something that was brought back to Objective-C from Swift. Check out iOS Designated Initializers : Using NS_DESIGNATED_INITIALIZER.

What the difference between designated and convenience init in this code below

The difference arises in subclasses; in what you've shown there is no usage difference.

“Convenience initializers must always delegate across” meaning in class A a convenience initializers calls a designated initializers in class A. “Designated initializers must always delegate up” meaning class B, a subclass of A, calls designated initializers in A.

Thus, in your 'part 2' both of the initializers in Food are available to subclasses of Food. But, in your 'part 1', only one initializer can be used in subclasses.

For example (Food in the following is your 'part 1'):

 21> class Fat : Food { 
22. init () {
23. super.init()
24. }
25. }
repl.swift:23:9: error: must call a designated initializer of the superclass 'Food'
super.init()
^

Quotes are: Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/us/jEUH0.l

NSWindowController designated initializer puzzle

According to the NSWindowController documentation:

You can also implement an NSWindowController subclass to avoid requiring client code to get the corresponding nib's filename and pass it to init(windowNibName:) or init(windowNibName:owner:) when instantiating the window controller. The best way to do this is to override windowNibName to return the nib's filename and instantiate the window controller by passing nil to init(window:). Using the init(window:) designated initializer simplifies compliance with Swift initializer requirements.

You can implement your class as:

class MyWindowController: NSWindowController
{
let thing: Thing

override var windowNibName: NSNib.Name? {
return NSNib.Name(rawValue: "MyNib")
}

init(thing: Thing) {
self.thing = thing

super.init(window: nil)
}

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

What are convenience required initializers in Swift?

A convenience required initializer is an initializer that is enforced onto all subclasses but is not the designated initializer. This means that said initializer will eventually call a designated initializer in its initialization chain.

Designated Initialisers

A designated initialiser is the canonical initializer for a class and the one which all required and convenience initialisers should call. The Docs say:

Designated initializers are the primary initializers for a class. A
designated initializer fully initializes all properties introduced by
that class and calls an appropriate superclass initializer to continue
the initialization process up the superclass chain.

Convenience Initialisers

A convenience initialiser is an initializer that sets up certain configuration information on a class...conveniently. Documentation:

Convenience initializers are secondary, supporting initializers for a
class. You can define a convenience initializer to call a designated
initializer from the same class as the convenience initializer with
some of the designated initializer’s parameters set to default values.
You can also define a convenience initializer to create an instance of
that class for a specific use case or input value type.

You do not have to provide convenience initializers if your class does
not require them. Create convenience initializers whenever a shortcut
to a common initialization pattern will save time or make
initialization of the class clearer in intent

Required Initialisers

Required initializers can be thought of as a binding contract between a parents interface and subsequent subclasses. Its your means of enforcing that all your children are aware of and implement a certain set of initialisers.

Write the required modifier before the definition of a class
initializer to indicate that every subclass of the class must
implement that initializer:



Related Topics



Leave a reply



Submit