Swift Init Accessors
In Swift 5.9, a Swift proposal 0400-init-accessors was implemented to allow us to use computed properties to initialize stored properties. That means we don’t need to expose local private stored properties to the constructor parameter list for initialization.
1 | struct AppState { |
In the example above, the AppState
has a computed property data
that we provide for outside accessing. But the actual stored property is the innerData
, the Xcode compiler will synthesize a construction initializer with the private property innerData
.
If we try to create an instance for the type AppState
, we will see a compilation error
1 | let state = AppState(innerData: 100) |
If we don’t want exposing the inner private properties to outside or we cannot modify construction initializers, we can use the init accessors
to initialize stored properties with computed properties.
1 | struct AppState { |
As you can see above, computed properties have a new attribute init
besides setter
and getter
. The init
attributer has one parameter that you can use to specify the initialized parameter’s name. There are extra two attributes initializes
and accesses
, the initializes
can receive multiple stored properties, that means initialize the computed property will also initialize these specified stored properties. In our example above, the Xcode compiler is intelligent enough to generate a construction initializer with the public property since the computed property data
will initialize the innerData
by the init accessor we defined.
The init
method in computed properties only be invoked once when objects are initialized. Then we assign new value to these computed properties will invoke their setters.
There is a more complicated example:
1 | struct AppState { |
The computed property three
can initialize the stored property two
and the computed property four
can initialize the stored property one
, so we can initialize the instance by only initializing the properties three
and four
. But we cannot exchange the initialization order of the two properties, the accesses
attributer means that the computed property four
needs the initialized property to finishing its initialization. Every stored properties specified in the accesses
attributer can be accessed in the init
block.
Actually, this feature is introduced for SwiftUI. In SwiftUI 5.0, the Swift team introduced a new observation framework called Observation
with a new macro attribute @Observable
. A value of class marked with @Observable
can be observed by SwiftUI views. Distinct to the ObservableObject
, a class with the macro @Observable
will expand all its properties to be individual observable objects.
The nuisance is that the macro @Observable
will synthesize multiple local stored properties into the class, but cannot modify constructors of the class. It will cause a compile error saying the constructor doesn’t initialize all stored properties of the class since all original stored properties were converted to computed properties.
The init accessor is a workaround for us to resolve various cases when we construct our own Macros.