Skip to content

Instantly share code, notes, and snippets.

@albertbori
Last active December 16, 2022 19:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save albertbori/4228bf583e3121cdd1e3403bb3f25bde to your computer and use it in GitHub Desktop.
Save albertbori/4228bf583e3121cdd1e3403bb3f25bde to your computer and use it in GitHub Desktop.
Swift Property Wrapper Implicit Initialization Scenarios
/*
This example shows how a simple property wrapper can be declared and initialized.
*/
@propertyWrapper
struct ExampleA<Value> {
private var value: Value
var wrappedValue: Value {
get { value }
set { value = newValue }
}
init(wrappedValue: Value) {
value = wrappedValue
}
}
struct ExampleAView: View {
@ExampleA var value: String
var body: some View {
Text(value)
}
}
struct ExampleAParentView: View {
var body: some View {
// default property wrapper initializer inferred from `init(wrappedValue: Value)`
ExampleAView(value: "Cool")
// not allowed, despite being allowed in other examples:
// ExampleAView(value: .init(wrappedValue: "Cool"))
}
}
/*
This example shows how a simple property wrapper can be extended to have an ancillary value.
It also shows how this affects how it is declared and initialized.
It also shows the limitations of being unable to split the value initialization from the declaration.
*/
@propertyWrapper
struct ExampleB<Value> {
private var value: Value
private var myValue: String
var wrappedValue: Value {
get { value }
set { value = newValue }
}
var projectedValue: String { myValue }
init(wrappedValue: Value, myValue: String) {
value = wrappedValue
self.myValue = myValue
}
}
struct ExampleBView: View {
@ExampleB(myValue: "Bar") var value: String = "Foo"
// not allowed (Missing argument for parameter 'wrappedValue' in call):
// @ExampleB(myValue: "Bar") var value: String
var body: some View {
Text(value) // Foo
Text($value) // Bar
}
}
struct ExampleB2View: View {
// note: this declaration implicitly relies on the view initializer to specify the details:
@ExampleB var value: String
var body: some View {
Text(value)
Text($value)
}
}
struct ExampleBParentView: View {
var body: some View {
// has a default value, so no value required:
ExampleBView()
// default property wrapper initializer inferred from `init(wrappedValue: Value, myValue: String)`:
ExampleBView(value: "Foo")
// manually initializing the property wrapper:
ExampleB2View(value: .init(wrappedValue: "Foo", myValue: "Bar"))
}
}
/*
This example shows how a property wrapper with an ancillary value can utilize default values.
*/
@propertyWrapper
struct ExampleC<Value> {
private var value: Value
private var myValue: String
var wrappedValue: Value {
get { value }
set { value = newValue }
}
var projectedValue: String { myValue }
init(wrappedValue: Value, myValue: String) {
value = wrappedValue
self.myValue = myValue
}
}
extension ExampleC where Value: ExpressibleByStringLiteral {
init(myValue: String) {
self.init(wrappedValue: "someDefaultValue", myValue: myValue)
}
}
struct ExampleCView: View {
@ExampleC(myValue: "Bar") var value: String = "Foo"
var body: some View {
Text(value) // Foo
Text($value) // Bar
}
}
struct ExampleC2View: View {
//note: This allows you to split the declaration between the parent initalizer and this property wrapper declaration
@ExampleC(myValue: "Bar") var value: String
var body: some View {
Text(value) // someDefaultValue
Text($value) // Bar
}
}
struct ExampleC3View: View {
@ExampleC var value: String
var body: some View {
Text(value)
Text($value)
}
}
struct ExampleCParentView: View {
var body: some View {
ExampleCView()
ExampleCView(value: "Foo")
ExampleC2View()
// not allowed:
// ExampleC2View(value: "Foo")
ExampleC2View(value: .init(myValue: "Bar"))
ExampleC2View(value: .init(wrappedValue: "Foo", myValue: "Bar"))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment