protocol Car { var wheels : Int { get set} init(wheels: Int) } extension Car { init(wheels: Int) { self.wheels = wheels } }
on self.wheels = wheels i get the error
Error: variable 'self' passed by reference before being initialized
How can I define the initializer in the protocol extension?
An initializer is a special type of function that is used to create an object of a class or struct. In Swift, we use the init() method to create an initializer.
Protocols let you describe what methods something should have, but don't provide the code inside. Extensions let you provide the code inside your methods, but only affect one data type – you can't add the method to lots of types at the same time.
In Swift, you can even extend a protocol to provide implementations of its requirements or add additional functionality that conforming types can take advantage of. For more details, see Protocol Extensions. Extensions can add new functionality to a type, but they can't override existing functionality.
Protocols provide a blueprint for Methods, properties and other requirements functionality. It is just described as a methods or properties skeleton instead of implementation. Methods and properties implementation can further be done by defining classes, functions and enumerations.
As you can see this doesn't work under these circumstances because when compiling, one has to make sure that all properties are initialized before using the struct/enum/class.
You can make another initializer a requirement so the compiler knows that all properties are initialized:
protocol Car { var wheels : Int { get set } // make another initializer // (which you probably don't want to provide a default implementation) // a protocol requirement. Care about recursive initializer calls :) init() init(wheels: Int) } extension Car { // now you can provide a default implementation init(wheels: Int) { self.init() self.wheels = wheels } } // example usage // mark as final final class HoverCar: Car { var wheels = 0 init() {} } let drivableHoverCar = HoverCar(wheels: 4) drivableHoverCar.wheels // 4
As of Xcode 7.3 beta 1 it works with structs
as expected but not with classes since if they are not final
the init(wheels: Int)
in the protocol is a required init
and it can be overridden therefore it cannot be added through an extension. Workaround (as the complier suggests): Make the class
final
.
final class
)To work with classes without making them final you can also drop the init(wheels: Int)
requirement in the protocol. It seems that it behaves no different than before but consider this code:
protocol Car { var wheels : Int { get set } init() // there is no init(wheels: Int) } extension Car { init(wheels: Int) { self.init() print("Extension") self.wheels = wheels } } class HoverCar: Car { var wheels = 0 required init() {} init(wheels: Int) { print("HoverCar") self.wheels = wheels } } // prints "HoverCar" let drivableHoverCar = HoverCar(wheels: 4) func makeNewCarFromCar<T: Car>(car: T) -> T { return T(wheels: car.wheels) } // prints "Extension" makeNewCarFromCar(drivableHoverCar)
So if you make a Car
from a generic context where the type on which you call init
is only to be known as Car
the extension initializer is called even though an initializer is defined in HoverCar
. This only occurs because there is no init(wheels: Int)
requirement in the protocol.
If you add it you have the former problem with declaring the class
as final
but now it prints two times "HoverCar". Either way the second problem probably never occurs so it might be a better solution.
Sidenote: If I have made some mistakes (code, language, grammar,...) you're welcome to correct me :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With