| Object Initialization |
| ===================== |
| |
| .. warning:: This document is incomplete and not up-to-date; it currently |
| describes the initialization model from Swift 1.0. |
| |
| .. contents:: |
| |
| Introduction |
| ------------ |
| |
| *Object initialization* is the process by which a new object is |
| allocated, its stored properties initialized, and any additional setup |
| tasks are performed, including allowing its superclass's to perform |
| their own initialization. *Object teardown* is the reverse process, |
| performing teardown tasks, destroying stored properties, and |
| eventually deallocating the object. |
| |
| Initializers |
| ------------ |
| |
| An initializer is responsible for the initialization of an |
| object. Initializers are introduced with the ``init`` keyword. For |
| example:: |
| |
| class A { |
| var i: Int |
| var s: String |
| |
| init int(i: Int) string(s: String) { |
| self.i = i |
| self.s = s |
| completeInit() |
| } |
| |
| func completeInit() { /* ... */ } |
| } |
| |
| Here, the class ``A`` has an initializer that accepts an ``Int`` and a |
| ``String``, and uses them to initialize its two stored properties, |
| then calls another method to perform other initialization tasks. The |
| initializer can be invoked by constructing a new ``A`` object:: |
| |
| var a = A(int: 17, string: "Seventeen") |
| |
| The allocation of the new ``A`` object is implicit in the |
| construction syntax, and cannot be separated from the call to the |
| initializer. |
| |
| Within an initializer, all of the stored properties must be |
| initialized (via an assignment) before ``self`` can be used in any |
| way. For example, the following would produce a compiler error:: |
| |
| init int(i: Int) string(s: String) { |
| completeInit() // error: variable 'self.i' used before being initialized |
| self.i = i |
| self.s = s |
| } |
| |
| A stored property with an initial value declared within the class is |
| considered to be initialized at the beginning of the initializer. For |
| example, the following is a valid initializer:: |
| |
| class A2 { |
| var i: Int = 17 |
| var s: String = "Seventeen" |
| |
| init int(i: Int) string(s: String) { |
| // okay: i and s are both initialized in the class |
| completeInit() |
| } |
| |
| func completeInit() { /* ... */ } |
| } |
| |
| After all stored properties have been initialized, one is free to use |
| ``self`` in any manner. |
| |
| Designated Initializers |
| ~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| There are two kinds of initializers in Swift: designated initializers |
| and convenience initializers. A *designated initializer* is |
| responsible for the primary initialization of an object, including the |
| initialization of any stored properties, *chaining* to one of its |
| superclass's designated initializers via a ``super.init`` call (if |
| there is a superclass), and performing any other initialization tasks, |
| in that order. For example, consider a subclass ``B`` of ``A``:: |
| |
| class B : A { |
| var d: Double |
| |
| init int(i: Int) string(s: String) { |
| self.d = Double(i) // initialize stored properties |
| super.init(int: i, string: s) // chain to superclass |
| completeInitForB() // perform other tasks |
| } |
| |
| func completeInitForB() { /* ... */ } |
| } |
| |
| Consider the following construction of an object of type ``B``:: |
| |
| var b = B(int: 17, string: "Seventeen") |
| |
| .. sidebar:: Note |
| |
| Swift differs from many other languages in that it requires one to |
| initialize stored properties *before* chaining to the superclass |
| initializer. This is part of Swift's memory safety guarantee, and |
| is discussed further in the section on `Three-Phase |
| Initialization`_. |
| |
| Initialization proceeds in several steps: |
| |
| 1. An object of type ``B`` is allocated by the runtime. |
| 2. ``B``'s initializer initializes the stored property ``d`` to |
| ``17.0``. |
| 3. ``B``'s initializer chains to ``A``'s initializer. |
| 4. ``A``'s initializer initialize's the stored properties ``i`` and |
| ``s``'. |
| 5. ``A``'s initializer calls ``completeInit()``, then returns. |
| 6. ``B``'s initializer calls ``completeInitForB()``, then returns. |
| |
| A class generally has a small number of designated initializers, which |
| act as funnel points through which the object will be |
| initialized. All of the designated initializers for a class must be |
| written within the class definition itself, rather than in an |
| extension, because the complete set of designated initializers is part |
| of the interface contract with subclasses of a class. |
| |
| The other, non-designated initializers of a class are called |
| convenience initializers, which tend to provide additional |
| initialization capabilities that are often more convenient for common |
| tasks. |
| |
| Convenience Initializers |
| ~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| A *convenience initializer* is an initializer that provides an |
| alternative interface to the designated initializers of a class. A |
| convenience initializer is denoted by the return type ``Self`` in the |
| definition. Unlike designated initializers, convenience initializers |
| can be defined either in the class definition itself or within an |
| extension of the class. For example:: |
| |
| extension A { |
| init() -> Self { |
| self.init(int: 17, string: "Seventeen") |
| } |
| } |
| |
| A convenience initializer cannot initialize the stored properties of |
| the class directly, nor can it invoke a superclass initializer via |
| ``super.init``. Rather, it must *dispatch* to another initializer |
| using ``self.init``, which is then responsible for initializing the |
| object. A convenience initializer is not permitted to access ``self`` |
| (or anything that depends on ``self``, such as one of its properties) |
| prior to the ``self.init`` call, although it may freely access |
| ``self`` after ``self.init``. |
| |
| Convenience initializers and designated initializers can both be used |
| to construct objects, using the same syntax. For example, the ``A`` |
| initializer above can be used to build a new ``A`` object without any |
| arguments:: |
| |
| var a2 = A() // uses convenience initializer |
| |
| Initializer Inheritance |
| ~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| One of the primary benefits of convenience initializers is that they |
| can be inherited by subclasses. Initializer inheritance eliminates the |
| need to repeat common initialization code---such as initial values of |
| stored properties not easily written in the class itself, or common |
| registration tasks that occur during initialization---while using the |
| same initialization syntax. For example, this allows a ``B`` object to |
| be constructed with no arguments by using the inherited convenience |
| initializer defined in the previous section:: |
| |
| var b2 = B() |
| |
| Initialization proceeds as follows: |
| |
| 1. A ``B`` object is allocated by the runtime. |
| 2. ``A``'s convenience initializer ``init()`` is invoked. |
| 3. ``A``'s convenience initializer dispatches to ``init int:string:`` |
| via the ``self.init`` call. This call dynamically resolves to |
| ``B``'s designated initializer. |
| 4. ``B``'s designated initializer initializes the stored property |
| ``d`` to ``17.0``. |
| 5. ``B``'s designated initializer chains to ``A``'s designated |
| initializer. |
| 6. ``A``'s designated initializer initialize's the stored properties |
| ``i`` and ``s``'. |
| 7. ``A``'s designated initializer calls ``completeInit()``, then |
| returns. |
| 8. ``B``'s designated initializer calls ``completeInitForB()``, then |
| returns. |
| 9. ``A``'s convenience initializer returns. |
| |
| Convenience initializers are only inherited under certain |
| circumstances. Specifically, for a given subclass to inherit the |
| convenience initializers of its superclass, the subclass must override |
| each of the designated initializers of its superclass. For example |
| ``B`` provides the initializer ``init int:string:``, which overrides |
| ``A``'s designated initializer ``init int:string:`` because the |
| initializer name and parameters are the same. If we had some other |
| subclass ``OtherB`` of ``A`` that did not provide such an override, it |
| would not inherit ``A``'s convenience initializers:: |
| |
| class OtherB : A { |
| var d: Double |
| |
| init int(i: Int) string(s: String) double(d: Double) { |
| self.d = d // initialize stored properties |
| super.init(int: i, string: s) // chain to superclass |
| } |
| } |
| |
| var ob = OtherB() // error: A's convenience initializer init() not inherited |
| |
| .. sidebar:: Note |
| |
| The requirement that a subclass override all of the designated |
| initializers of its superclass to enable initializer inheritance is |
| crucial to Swift's memory safety model. See `Initializer |
| Inheritance Model`_ for more information. |
| |
| Note that a subclass may have different designated initializers from |
| its superclass. This can occur in a number of ways. For example, the |
| subclass might override one of its superclass's designated |
| initializers with a convenience initializer:: |
| |
| class YetAnotherB : A { |
| var d: Double |
| |
| init int(i: Int) string(s: String) -> Self { |
| self.init(int: i, string: s, double: Double(i)) // dispatch |
| } |
| |
| init int(i: Int) string(s: String) double(d: Double) { |
| self.d = d // initialize stored properties |
| super.init(int: i, string: s) // chain to superclass |
| } |
| } |
| |
| var yab = YetAnotherB() // okay: YetAnotherB overrides all of A's designated initializers |
| |
| In other cases, it's possible that the convenience initializers of the |
| superclass simply can't be made to work, because the subclass |
| initializers require additional information provided via a |
| parameter that isn't present in the convenience initializers of the |
| superclass:: |
| |
| class PickyB : A { |
| var notEasy: NoEasyDefault |
| |
| init int(i: Int) string(s: String) notEasy(NoEasyDefault) { |
| self.notEasy = notEasy |
| super.init(int: i, string: s) // chain to superclass |
| } |
| } |
| |
| Here, ``PickyB`` has a stored property of a type ``NoEasyDefault`` |
| that can't easily be given a default value: it has to be provided as a |
| parameter to one of ``PickyB``'s initializers. Therefore, ``PickyB`` |
| takes over responsibility for its own initialization, and |
| none of ``A``'s convenience initializers will be inherited into |
| ``PickyB``. |
| |
| Synthesized Initializers |
| ~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| When a particular class does not specify any designated initializers, |
| the implementation will synthesize initializers for the class when all |
| of the class's stored properties have initial values in the class. The |
| form of the synthesized initializers depends on the superclass (if |
| present). |
| |
| When a superclass is present, the compiler synthesizes a new |
| designated initializer in the subclass for each designated initializer |
| of the superclass. For example, consider the following class ``C``:: |
| |
| class C : B { |
| var title: String = "Default Title" |
| } |
| |
| The superclass ``B`` has a single designated initializer,:: |
| |
| init int(i: Int) string(s: String) |
| |
| Therefore, the compiler synthesizes the following designated |
| initializer in ``C``, which chains to the corresponding designated |
| initializer in the superclass:: |
| |
| init int(i: Int) string(s: String) { |
| // title is already initialized in the class C |
| super.init(int: i, string: s) |
| } |
| |
| The result of this synthesis is that all designated initializers of |
| the superclass are (automatically) overridden in the subclass, |
| becoming designated initializers of the subclass as well. Therefore, |
| any convenience initializers in the superclass are also inherited, |
| allowing the subclass (``C``) to be constructed with the same |
| initializers as the superclass (``B``):: |
| |
| var c1 = C(int: 17, string: "Seventeen") |
| var c2 = C() |
| |
| When the class has no superclass, a default initializer (with no |
| parameters) is implicitly defined:: |
| |
| class D { |
| var title = "Default Title" |
| |
| /* implicitly defined */ |
| init() { } |
| } |
| |
| var d = D() // uses implicitly-defined default initializer |
| |
| Required Initializers |
| ~~~~~~~~~~~~~~~~~~~~~ |
| |
| Objects are generally constructed with the construction syntax |
| ``T(...)`` used in all of the examples above, where ``T`` is the name |
| of the type. However, it is occasionally useful to construct an object |
| for which the actual type is not known until runtime. For example, one |
| might have a ``View`` class that expects to be initialized with a |
| specific set of coordinates:: |
| |
| struct Rect { |
| var origin: (Int, Int) |
| var dimensions: (Int, Int) |
| } |
| |
| class View { |
| init frame(Rect) { /* initialize view */ } |
| } |
| |
| The actual initialization of a subclass of ``View`` would then be |
| performed at runtime, with the actual subclass being determined via |
| some external file that describes the user interface. The actual |
| instantiation of the object would use a type value:: |
| |
| func createView(_ viewClass: View.Type, frame: Rect) -> View { |
| return viewClass(frame: frame) // error: 'init frame:' is not 'required' |
| } |
| |
| The code above is invalid because there is no guarantee that a given |
| subclass of ``View`` will have an initializer ``init frame:``, because |
| the subclass might have taken over its own initialization (as with |
| ``PickyB``, above). To require that all subclasses provide a |
| particular initializer, use the ``required`` attribute as follows:: |
| |
| class View { |
| @required init frame(Rect) { |
| /* initialize view */ |
| } |
| } |
| |
| func createView(_ viewClass: View.Type, frame: Rect) -> View { |
| return viewClass(frame: frame) // okay |
| } |
| |
| The ``required`` attribute allows the initializer to be used to |
| construct an object of a dynamically-determined subclass, as in the |
| ``createView`` method. It places the (transitive) requirement on all |
| subclasses of ``View`` to provide an initializer ``init frame:``. For |
| example, the following ``Button`` subclass would produce an error:: |
| |
| class Button : View { |
| // error: 'Button' does not provide required initializer 'init frame:'. |
| } |
| |
| The fix is to implement the required initializer in ``Button``:: |
| |
| class Button : View { |
| @required init frame(Rect) { // okay: satisfies requirement |
| super.init(frame: frame) |
| } |
| } |
| |
| Initializers in Protocols |
| ~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| Initializers may be declared within a protocol. For example:: |
| |
| protocol DefaultInitializable { |
| init() |
| } |
| |
| .. sidebar:: Note |
| |
| Initializers in protocols have not yet been implemented. Stay tuned. |
| |
| A class can satisfy this requirement by providing a required |
| initializer. For example, only the first of the two following classes |
| conforms to its protocol:: |
| |
| class DefInit : DefaultInitializable { |
| @required init() { } |
| } |
| |
| class AlmostDefInit : DefaultInitializable { |
| init() { } // error: initializer used for protocol conformance must be 'required' |
| } |
| |
| The ``required`` requirement ensures that all subclasses of the class |
| declaring conformance to the protocol will also have the initializer, |
| so they too will conform to the protocol. This allows one to construct |
| objects given type values of protocol type:: |
| |
| func createAnyDefInit(_ typeVal: DefaultInitializable.Type) -> DefaultInitializable { |
| return typeVal() |
| } |
| |
| De-initializers |
| ~~~~~~~~~~~~~~~ |
| |
| While initializers are responsible for setting up an object's state, |
| *de-initializers* are responsible for tearing down that state. Most |
| classes don't require a de-initializer, because Swift automatically |
| releases all stored properties and calls to the superclass's |
| de-initializer. However, if your class has allocated a resource that |
| is not an object (say, a Unix file descriptor) or has registered |
| itself during initialization, one can write a de-initializer using |
| ``deinit``:: |
| |
| class FileHandle { |
| var fd: Int32 |
| |
| init withFileDescriptor(fd: Int32) { |
| self.fd = fd |
| } |
| |
| deinit { |
| close(fd) |
| } |
| } |
| |
| The statements within a de-initializer (here, the call to ``close``) |
| execute first, then the superclass's de-initializer is |
| called. Finally, stored properties are released and the object is |
| deallocated. |
| |
| Methods Returning ``Self`` |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| |
| A class method can have the special return type ``Self``, which refers |
| to the dynamic type of ``self``. Such a method guarantees that it will |
| return an object with the same dynamic type as ``self``. One of the |
| primary uses of the ``Self`` return type is for factory methods:: |
| |
| extension View { |
| class func createView(_ frame: Rect) -> Self { |
| return self(frame: frame) |
| } |
| } |
| |
| .. sidebar:: Note |
| |
| The return type ``Self`` fulfills the same role as Objective-C's |
| ``instancetype``, although Swift provides stronger type checking for |
| these methods. |
| |
| Within the body of this class method, the implicit parameter ``self`` |
| is a value with type ``View.Type``, i.e., it's a type value for the |
| class ``View`` or one of its subclasses. Therefore, the restrictions |
| are the same as for any value of type ``View.Type``: one can call |
| other class methods and construct new objects using required |
| initializers of the class, among other things. The result returned |
| from such a method must be derived from the type of ``Self``. For |
| example, it cannot return a value of type ``View``, because ``self`` |
| might refer to some subclass of ``View``. |
| |
| Instance methods can also return ``Self``. This is typically used to |
| allow chaining of method calls by returning ``Self`` from each method, |
| as in the builder pattern:: |
| |
| class DialogBuilder { |
| func setTitle(_ title: String) -> Self { |
| // set the title |
| return self; |
| } |
| |
| func setBounds(_ frame: Rect) -> Self { |
| // set the bounds |
| return self; |
| } |
| } |
| |
| var builder = DialogBuilder() |
| .setTitle("Hello, World!") |
| .setBounds(Rect(0, 0, 640, 480)) |
| |
| |
| Memory Safety |
| ------------- |
| |
| Swift aims to provide memory safety by default, and much of the design |
| of Swift's object initialization scheme is in service of that |
| goal. This section describes the rationale for the design based on the |
| memory-safety goals of the language. |
| |
| Three-Phase Initialization |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| The three-phase initialization model used by Swift's initializers |
| ensures that all stored properties get initialized before any code can |
| make use of ``self``. This is important uses of ``self``---say, |
| calling a method on ``self``---could end up referring to stored |
| properties before they are initialized. Consider the following |
| Objective-C code, where instance variables are initialized *after* the |
| call to the superclass initializer:: |
| |
| @interface A : NSObject |
| - (instancetype)init; |
| - (void)finishInit; |
| @end |
| |
| @implementation A |
| - (instancetype)init { |
| self = [super init]; |
| if (self) { |
| [self finishInit]; |
| } |
| return self; |
| } |
| @end |
| |
| @interface B : A |
| @end |
| |
| @implementation B { |
| NSString *ivar; |
| } |
| |
| - (instancetype)init { |
| self = [super init]; |
| if (self) { |
| self->ivar = @"Default name"; |
| } |
| return self; |
| } |
| |
| - (void) finishInit { |
| NSLog(@"ivar has the value %@\n", self->ivar); |
| } |
| @end |
| |
| .. sidebar:: Notes |
| |
| In Objective-C, ``+alloc`` zero-initializes all of the instance |
| variables, which gives them predictable behavior before the init |
| method gets to initialize them. Given that Objective-C is fairly |
| resilient to ``nil`` objects, this default behavior eliminates (or |
| hides) many such initialization bugs. In Swift, however, the |
| zero-initialized state is less likely to be valid, and the memory |
| safety goals are stronger, so zero-initialization does not suffice. |
| |
| When initializing a ``B`` object, the ``NSLog`` statement will print:: |
| |
| ivar has the value (null) |
| |
| because ``-[B finishInit]`` executes before ``B`` has had a chance to |
| initialize its instance variables. Swift initializers avoid this issue |
| by splitting each initializer into three phases: |
| |
| 1. Initialize stored properties. In this phase, the compiler verifies |
| that ``self`` is not used except when writing to the stored properties |
| of the current class (not its superclasses!). Additionally, this |
| initialization directly writes to the storage of the stored |
| properties, and does not call any setter or ``willSet``/``didSet`` |
| method. In this phase, it is not possible to read any of the stored |
| properties. |
| |
| 2. Call to superclass initializer, if any. As with the first step, |
| ``self`` cannot be accessed at all. |
| |
| 3. Perform any additional initialization tasks, which may call methods |
| on ``self``, access properties, and so on. |
| |
| Note that, with this scheme, ``self`` cannot be used until the |
| original class and all of its superclasses have initialized their |
| stored properties, closing the memory safety hole. |
| |
| |
| Initializer Inheritance Model |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| FIXME: To be written |
| |
| Objective-C Interoperability |
| ---------------------------- |
| |
| Initializers and Init Methods |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| Designated and Convenience Initializers |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| Allocation and Deallocation |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| Dynamic Subclassing |
| ~~~~~~~~~~~~~~~~~~~ |