Property Wrappers
Tags: swift, basics, property, wrappers
Published: 2020-08-20 20:55:30

If you have work with **SwiftUI**, you may see these couple of properties that begin with `@State`.

Well, this works as a property wrapper!.

Let's dive in, to get involved with this kind of properties we must know about **value semantics**.

## Value Semantics

When your type supports *value semantics*, it means that you are watching that variable specifically, it guarantees the independence of variables.

These are related to *value types* (ex. `structs`).

> **Reference types** and **Value types** differ in their **assignment behavior**, with *reference* we are pointing to the same reference, hash, address, unlike *value* we are just creating a new copy of our instance.

### Reference Type

```swift
class ReferencePerson {

  var name: String

  init(name: String) {
    self.name = name
  }
}

var referencePerson1 = ReferencePerson(name: "Juan")
var referencePerson2 = referencePerson1

referencePerson2.name = "Ethan"

referencePerson1.name // output: "Ethan"
referencePerson2.name // output: "Ethan"
```

### Value Type

```swift
struct ValuePerson {

  var name: String
}

var valuePerson1 = ValuePerson(name: "Juan")
var valuePerson2 = valuePerson1

valuePerson2.name = "Ethan"

valuePerson1.name // output: "Juan"
valuePerson2.name // output: "Ethan"
```

## Value Types containing Reference Types

We could combine these two types on one, so we would expect that if we are containing a reference inside a value type, the assignment should be copy.

Let's take an example.

```swift
class Person {

  var name: String

  init(name: String) {
    self.name = name
  }
}

struct Dog {

  var name: String
  var owner: Person
}
``` 

Let's use these two classes, as you can see `Dog` is of type `struct` and `Person` is of type `class`.

```swift
var husky = Dog(name: "Jay-Jay", owner: Person(name: "Mike"))
var pug = husky

pug.owner.name = "Michell"

husky.owner.name // output: "Michell"
pug.owner.name // output: "Michell"
```

Oh-oh!, what happened? - Well, although we are creating a copy, our `Person` is pointing to the same reference.

But we have a solution to solve this, so here is where we meet **Copy-on-write**!

## Copy-on-write

With **copy-on-write** we can validate what we really need to have value semantics, at the example above, the **owner's name**.

So, let's modify our `Dog` class.

```swift
struct Dog {

  var name: String

  private var owner: Person = Person()

  var ownerName: String {
    get { owner.name }
    set { owner = Person(name: newValue) }
  }

  init(name: String, ownerName: String) {
    self.name = name
    self.ownerName = ownerName
  }
}
```

Take a look at this.

```swift
private var owner: Person = Person()

  var ownerName: String {
    get { owner.name }
    set { owner = Person(name: newValue) }
  }
```

This is the magic of copy on write, now if we try to instantiate our values.

```swift
var husky = Dog(name: "Jay-Jay", ownerName: "Mike")
var pug = husky

pug.ownerName = "Michell"

husky.ownerName // output: "Mike"
pug.ownerName // output: "Michell"
```

The idea is as simple as just create a new backup and drop the old one, but there is something more to help with performance.

> Of course there is much more under the hood about using **Copy-on-write** than just create a backup and drop the old one.

What if we are not referencing nothing more? - For the example before, if we just have the `husky` instance doesn't make sense to be creating new instances each time we change the value, for that part we have `isKnownUniquelyReferenced(_ object:)` this is a `generic` function that checks if our instance is unique or it has other references, so let's change our `set` from our `ownerName` property like this.

```swift
var ownerName: String {
    get { owner.name }
    set {
      if isKnownUniquelyReferenced(&owner) {
        owner.name = ownerName
      } else {
        owner = Person(name: newValue)
      }
    }
}
```

## Property Wrappers - in action

Now, you could be thinking, ok... now I know some about **Value Semantics**, about **copy-on-write**, what about **Property wrappers**?.

To introduce these properties let's create our **Property Wrapper** of the magic code of **copy-on-write**.

```swift
@propertyWrapper
struct CopyOnWriteOwnerName {

  private var person: Person

  var wrappedValue: String {
    get { person.name }
    set {
      if isKnownUniquelyReferenced(&person) {
        person.name = newValue
      } else {
        person = Person(name: newValue)
      }
    }
  }

  init(wrappedValue: String) {
    self.person = Person(name: wrappedValue)
  }
}
```

Do you see that is the same code? - Well, now that we have encapsulated our **copy-on-write** code, let's use it, thanks to `@propertyWrapper`

We can use it inside our `Dog` struct, like this.

```swift
struct Dog {

  var name: String
  @CopyOnWriteOwnerName var ownerName: String
}
```

And now! our code was encapsulated, it is now short, and much easier to understand!.

Do you get now what **property wrapper** is?

👨‍💻 Happy coding devs! 👨‍💻