Swift initializer for public class - swift

When creating a public class, is it necessary to make the designated initializer public?
What's the difference between making it public vs not?
e.g.
public class A {
init() {}
}
or
public class A {
public init() {}
}

No
You do not need to make it public. In fact, you can make it private. The only thing special about a designated initializer (and your classes are allowed more than one) is that they are responsible for ensuring the object is fully initialized.
A convenience initializer (an initializer is either designated or convenience) (marked by the convenience keyword) does not have this responsibility. A convenience initializer delegates to a designated initializer first, and then after that returns, it is given the opportunity to overwrite some of the initial values. Importantly, the convenience initializer must always "delegate across". It must always call another initializer within the class.
By contrast, a designated initializer (any initializer not marked with the convenience keyword) must take responsibility for making sure every property in the class gets a valid initial value, then it must "delegate up" (call a super class initializer, if there is a super class), then it can overwrite values if it wants.
But nothing prevents you from create a class with nothing but private designated initializers (nothing at all).
Even when we are inheriting from a class with a required initializer, our subclass can simply implement that initializer as a convenience initializer.
class ParentClass {
let foo: Int
required init(foo: Int) {
self.foo = foo
}
}
class ChildClass: ParentClass {
let bar: Int
private init(foo: Int, bar: Int) {
self.bar = bar
super.init(foo: foo)
}
required convenience init(foo: Int) {
self.init(foo: foo, bar: foo)
}
}
The above is perfectly valid Swift.
ChildClass has a private designated initializer. It has inherited from a parent class with a required initializer, but it has implemented that initializer as a convenience initializer. (Moreover, in contrast to your conjecture in a comment here and a question else where, the required initializer doesn't actually have to be public necessarily... context matters, and perhaps I will expand on that in an answer to your other question.)
Moreover, in direct contrast to subjective_c's answer, you don't have to make parts of your Swift code public in order to use that code from Objective-C, and the passage from Apple he has quoted in his answer actually indicates that. You only need to mark public the things you want to be available outside of the framework in which your code has been implemented. You can put Objective-C & Swift code within the same application and the Objective-C code can see anything marked as public or internal.

You don't need to make it public unless you are making it available as a framework for usage in Objective-C as well.
See: https://developer.apple.com/swift/blog/?id=5
When mixing Objective-C and Swift, because the generated header for a
framework is part of the framework’s public Objective-C interface,
only declarations marked public appear in the generated header for a
Swift framework.

Related

Swift 3: private required initializer possible?

Consider following code:
private class MyClass {
private required init(_ i: Int) {
}
}
Now, I'm getting compiler error:
'required' initializer must be as accessible as its enclosing type. But the type is declared as private.
I thought the issue might be that the class is declared on a file level, so it's
private type
restricts the use of an entity to the enclosing declaration.
as documentation says. So it effectively makes it fileprivate, since the enclosing declaration is a file. But I'm getting the same error even for nested private classes.
When I declare initializer as fileprivate it works:
private class MyClass {
private class MyNested {
fileprivate required init(_ i: Int) {
}
}
}
Question: why private is not correct here? Is it possible to declare private required initializer?
I ask because I want to understand the error in the first place.
Why I need it is rather different question, but initially I wrote such code:
private class MyClass {
private class MyNested {
private init(_ i: Int) {
}
func foo() {
var f = type(of: self).init(1)
}
}
}
and then had to add required declaration specifier as I was getting the error: constructing an object of class type 'MyClass.MyNested' with a metatype value must use a 'required' initializer
Answer:
Thanks to #SørenMortensen:
The issue with the private initialiser is that the MyNested class is accessible within MyClass, but the initialiser is only accessible within MyNested, and therefore is not as accessible as its enclosing type. And as #Hamish points out, the concept of a required initialiser is mutually exclusive with the concept of a private initialiser.
So it looks like it is not possible to have private required initializer, indeed. And in my case I can make MyNested class to be final and then make the initializer private not making it required.
Why would you want one?
The purpose of required means that one is forced to use this initialization when declaring this class. Like #Hamish said, setting it as private would just result in classes unable to see it and cannot declare it. If you want additional setup but don't want it to be accessible, why not just call a private func within a required init?

Understanding init() when sub-classing in Swift

How can I add a custom initializer when inheriting from a class that already has an initializer?
What I have is a Vehicle class which has an itializer who takes an argument name. What I want to do is inherit from this Vehicleclass, create another initializer for the new class but keep using the existing initializer.
Base Class (No problem here):
class Vehicle{
var make:String
init(make:String){
self.make = make
}
}
New Class (Doesn't work):
// Not sure how to structure this class
class Car:Vehicle {
var engine:Double
override init(){
super.init()
}
init(engine:Double){
self.engine = engine
}
}
This is what I would like to be able to do... re-use the existing initializer plus the new one.
let cobalt = Car(make:"Chevy" engine: 2.5)
Any designated initializer in a subclass must call a designated initializer from its immediate superclass:
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
...
From the Swift Language Guide - Initialization.
Hence, you could construct your designated initializer of Car to take two arguments, make and engine, and use the latter to inititalize the member property engine of the subclass, thereafter call the designated initializer of the superclass using the supplied make parameter (supplied to subclass initializer) as argument to the superclass initializer.
class Car: Vehicle {
var engine: Double
init(make: String, engine:Double){
self.engine = engine
super.init(make: make)
}
}

Swift: "failable initializer 'init()' cannot override a non-failable initializer" vs. default parameters

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.
This is how I solved the problem for me:
I can declare
public convenience init?(_: Void) { self.init(x: nil) }
and use it like
let b = B(())
or even
let b = B()
— which is logical since its signature is (kind of) different, so no overriding here. Only using a Void parameter and omitting it in the call feels a bit strange… But the end justifies the means, I suppose. :-)
After a bit of fiddling I think I understand. Let's consider a protocol requiring this initializer and a class implementing it:
protocol I {
init()
}
class A : I {
init() {}
}
This gives the error: "Initializer requirement 'init()' can only be satisfied by a required initializer in non-final class 'A'". This makes sense, as you could always declare a subclass of A that doesn't inherit that initializer:
class B : A {
// init() is not inherited
init(n: Int) {}
}
So we need to make our initializer in A required:
class A : I {
required init() {}
}
Now if we look at the NSObject interface we can see that the initializer is not required:
public class NSObject : NSObjectProtocol {
[...]
public init()
[...]
}
We can confirm this by subclassing it, adding a different initializer and trying to use the normal one:
class MyObject : NSObject {
init(n: Int) {}
}
MyObject() // Error: Missing argument for parameter 'n:' in call
Now here comes the weird thing: We can extend NSObject to conform to the I protocol, even though it doesn't require this initializer:
extension NSObject : I {} // No error (!)
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:
extension I {
static func get() -> Self { return Self() }
}
MyObject.get()
// Runtime error: use of unimplemented initializer 'init()' for class '__lldb_expr_248.MyObject'
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 override keyword 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:
public convenience override init() { self.init(x: nil)! }
Also have a look at the Initialization section of the Swift reference.

Meaning of the convenience keyword in Swift

When I go back to look at some of Apple's Sprite Kit documentation I see a lot of occasions where a keyword called convenience comes up. For Example
convenience init(texture texture: SKTexture?, size size: CGSize)
What does it mean?
Convenience initialisers allow you to initialise a class without all the required parameters the designated initialiser needs.
For example, in a very basic example you may have a designated initialiser for a class that requires a String:
init someName(value: String) {
You could also create a convenience initialiser to go along side this that takes an int and converts it to a String and then calls the designated initialiser and passes it that String. This way if your class is initialised and passed an int instead or by mistake, it won't error and will handle it.
convenience init someName2(value: Int) {
let someString = String(value)
someName(value: someString)
}
Another use for them is that the designated initialiser may take multiple parameters. You could create a convenience initialiser to go along side this that takes only one of those parameters, creates the others and sets them to some default values and then calls the designated initialiser, passing them all in. This way you do not need to specify all required parameters of the designated initialiser since if you don't, your convenience initialiser will fill in missing ones with default values.
convenience init someName(value: String) {
someName(value: someString, value2: "DefaultValue")
}
init someName(value: String, value2: String) {
That is a convenience initializer.
From the docs:
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.
An initializer that is not marked convenience is a designated initializer:
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.
The docs I linked above are very detailed, because there is a lot to initialization. You'll need to read them to really understand what's going on. But to give an example, let's say you create a car class:
class Car {
let numberOfWheels: Int
init(numberOfWheels: Int) {
self.numberOfWheels = numberOfWheels
}
convenience init() {
self.init(numberOfWheels: 4)
}
}
The car class contains two initializers - a designated initializer and a convenience initializer.
The designated initializer is simply marked init. Inside a designated initializer, you are required to set all class properties so that the class is ready to go once initialization finishes. We set numberOfWheels inside our initializer.
The convenience initializer is marked convenience init. A convenience initializer may do whatever, but it must call one of the designated initializers before it finishes. In our example, it calls self.init(numberOfWheels: Int) and supplies a default number of wheels (4).
Convenience initializers are there exactly for their namesake: convenience. They allow you to set up initializers to classes that deal with common initialization cases. In our Car class, it is typical for a car to have four wheels, so our convenience initializer makes that common case easier.
To create a car, we can use either the designated initializer or the convenience initializer:
let carA = Car(numberOfWheels: 3) // makes a car with 3 wheels
let carB = Car() // makes a car with 4 wheels
There are a lot more rules around initialization, especially in class hierarchies where super.init and initializer inheritance must be considered as well. I cannot describe them all any better or more succinctly than the official documentation, so again, I suggest you check there.
Default 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.
as per the Swift Documentation
Actually - Swift defines two kinds of initializers.
Designated initializers
Convenience initializers
Designated initializers are the primary initializers for a class. Every class should have at least one designated initializer.
init(parameters if any) {
}
Convenience initializers are secondary, supporting initializers for a class. Convenience initializers are written in the same style, but with the convenience modifier placed before the init keyword, separated by a space:
convenience init(parameters if any) {
}
Convenience init initializes the designated init method by calling self.init.
Example:
class HumanBeing {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: “not set”)
// Convenience init call the designated init method
}
}
let humanBeingObj1 = HumanBeing() // calls convenience init
let humanBeingObj2 = HumanBeing(name: “abhilash”) // calls designated init

Why use required Initializers in Swift classes?

I am trying to understand the use of the required keyword in Swift classes.
class SomeClass
{
required init() {
// initializer implementation goes here
}
}
required doesn't force me to implement the method in my child-class. If I want to override the required designated initializer of my parent class I need to write required and not override. I know how it works but can not understand why I should do this.
What is the benefit of required?
As far as I can tell, languages like C# don't have something like this and work just fine with override.
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.
According to the documentation:
Write the required modifier before the definition of a class initializer to
indicate that every subclass of the class must implement that initializer
So yes, required does force all child classes to implement this constructor. However, this is not needed
if you can satisfy the requirement with an inherited initializer.
So if you have created more complex classes that cannot be fully initialized with a parent constructor, you must implement the require constructor.
Example from documentation (with some added stuff):
class SomeClass {
required init() {
// initializer implementation goes here
}
}
class SomeSubclass: SomeClass {
let thisNeedsToBeInitialized: String
required init() {
// subclass implementation of the required initializer goes here
self.thisNeedsToBeInitialized = "default value"
}
}
I want to draw an attention on another solution provided by Required, apart from Matt has given above.
class superClass{
var name: String
required init(){
// initializer implementation goes here
self.name = "Untitled"
}
}
class subClass: superClass {
var neakName: String = "Subclass Untitled"
}
let instanceSubClass = subClass()
instanceSubClass.name //output: "Untitled"
instanceSubClass.neakName //output: "Subclass Untitled"
As you can check in above example, I've declared required init() on superClass, init() initializer of superClass has inherited by default on subClass, So you able to create an instance of subClass let instanceSubClass = subClass().
But, suppose you want to to add one designated initializer on subClass to assign run time value to stored property neakName. Of course you can add it, but that will result to no initializers from the superClass will be inherited to subClass, So if you will create an instance of subClass you will create through its own designated initializer as below.
class superClass{
var name: String
init(){
// initializer implementation goes here
self.name = "Untitled"
}
}
class subClass: superClass {
var neakName: String = "Subclass Untitled"
init(neakName: String) {
self.neakName = neakName
}
}
let instanceSubClass = subClass(neakName: "Bobby")
instanceSubClass.name //output: "Untitled"
instanceSubClass.neakName //output: "Bobby"
Here above, you won't be able to create an instance of subClass by just subClass(), But if you want that every subclasses of superClass must have their own init() initializer to create direct instance by subClass(). Just place required keyword before init() on superClass, it will force you to add init() initializer on subClass too - as below.
class superClass{
var name: String
required init(){
// initializer implementation goes here
self.name = "Untitled"
}
}
class subClass: superClass {
var neakName: String = "Subclass Untitled"
init(neakName: String) {
self.neakName = neakName
}
} // Compiler error <------------ required `init()` must be provided by subClass.
let instanceSubClass = subClass(neakName: "Bobby")
instanceSubClass.name //output: "Untitled"
instanceSubClass.neakName //output: "Bobby"
SO, use required keyword before initializer on superclass, when you want all subclasses must have been implemented required initializer of superclass.
If you are trying to add you own initialiser in the sub class, then you have to follow certain things those were declared in super class. So it make sure that you will not forget to implement that required method. If you forget compiler will give you error // fatal error, we've not included the required init()
. Another reason is it creates a set of conditions that ever sub class should follow it the sub class is defining its own initialiser.