Property wrappers

In the way up of discovering SwiftUI and Combine, we will have to get along with property wrappers. Property wrappers was a language feature introduced in Swift 5.1, a feature that would be heavily used for SwiftUI and Combine. 

Contents of this article:

  • What is a property wrapper?
  • Anatomy of property wrappers
  • Limitations of property wrappers
  • Conclusions

What is a property wrapper?

As per documentation, a property wrapper is a layer of separation between code that manages how a property is stored and the code that defines a property . Initially, property wrappers were named property delegates , so we can think about property wrappers as a property that delegates its get and set to another type. The main goal, is to reuse implementation patterns in a easy way, hence reducing boiler plate code.

Anatomy of property wrappers

In order to understand the anatomy of property wrappers, let’s first see an implementation of one of the typical implementation pattern in use, transforming a value, but without using property wrappers. This old style wrapper provides as with the possibility to get capitalized text.

// Old style wrapper
struct CapitalizeString {
    private var _text: String
    init(text: String) {
        _text = text
    }
    var text: String {
        get {
            return _text.capitalized
        }
        set {
            _text = newValue
        }
    }
}

This wrapper, can be used like this:

struct TextToCapitalize {
    var text: CapitalizeString
}

let capitalizeString = CapitalizeString(text: "")
var text = TextToCapitalize(text: capitalizeString)
text.text.text = "house"
print(text.text.text)
"House"

What do we need in order to create a property wrapper and improve the old way? When declaring the struct, enum or class, will be preceded by the keyword @propertyWrapper, and a wrappedValue property, as follow:

@propertyWrapper
struct CapitalizeStringWrapper {
    private var text: String
    init(wrappedValue: String)  {
        self.text = wrappedValue
    }
    var wrappedValue: String {
        get {
            text.capitalized
        }
        set {
            text = newValue
        }
    }
}

And it would be used like this:

struct NameToCapitalize {
    @CapitalizeStringWrapper var name: String
}

var name = NameToCapitalize(name: "iker")
print(name.name)
"Iker"

Much cleaner and straight forward, don’t you think? Sweet syntactic sugar.

Additionally, we can expose functionality of the property wrapper through the definition of a projected value. Following the CapitalizeStringWrapper example we could add a function to uppercase the text, and expose it with a projected value:

@propertyWrapper
struct CapitalizeStringWrapper {
    private var text: String
    
    var projectedValue: CapitalizeStringWrapper { return self }
    
    init(wrappedValue: String)  {
        self.text = wrappedValue
    }

    var wrappedValue: String {
        get {
            return text.capitalized
        }
        set {
            text = newValue.capitalized
        }
    }
    
    func uppercase() -> String {
        return self.text.uppercased()
    }
}

In order to access this new functionality, we use dollar sing to access the wrapper projection:

struct TextToUpperCase {
    @CapitalizeStringWrapper var name: String
}

var name = TextToUpperCase(name: "iker")
print(name.$name.uppercase())
"IKER"

With the projected value, we enable to access functionality from outside, but it is also possible to access it from inside the type that use the property wrapper like this:

struct TextToUpperCase {
    @CapitalizeStringWrapper var name: String
    
    func uppercase() {
        _name.uppercase()
    }
}

Since Swift 5.4, which will be the default Swift version in the upcoming release of Xcode 12.5, it is possible to use a property wrapper as a local variable like this:

struct TextToUpperCase {
    @CapitalizeStringWrapper var name: String
    
    func uppercase() {
        @CapitalizeStringWrapper var upperCasedName = "iker"
    }
}

Limitations of property wrappers:

While property wrappers might be very helpful, and a must in the future of Swift, it has its downsides:

  • A property wrapper cannot be declared in a protocol or an extension (Ouch!).
  • We cannot use typealias with property wrappers (Too much syntactic sugar may be?)
  • Property wrappers are difficult to compose.
  • It is not possible to override properties with wrapper properties.

Conclusion

As seen in this article, property wrappers helps us to reduce boiler plate, but as well can make the code more difficult to understand. Wether if we like it or not, it is a fact that we have to get use to it to understand SwiftUI mostly and Combine.

And that’s a wrap!

Comments, typos, errors?

Please, if you see any error, typo, way to improve it, or just one to say Hi, don’t hesitate to contact!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: