Understanding Property Wrappers Swift

Property Wrappers


Property wrappers in swift help us to separate the code that manages the validation and the code that actually defines it.


Code that defines the property


var userIdInt

Code that manages the storage

@UserIdentifier var userId: Int



@UserIdentifier is a custom way to manage the storage. Don't worry it will be more clear in some time, but my whole point was to clear the understanding on the difference between defining and managing a property (with the help of Property Wrapper). 


Consider a use case of UserIdentifier:


  1. We want to have a userId which can take maximum up to 100 ids.
  2. If a user tries to set it to a value more than 100, it won't allow
  3. Provide a validation flag if value exceeds then 100. i.e true if any adjustments made or else false. 


Think of this validation to be added at 5 different properties of different class. It would be very difficult to manage , may be write extension to handle this. 


extension Int {

    func validateMax() -> Int {

        if self > 100 {

            return 100

        }

        return self

    }

}


Probably not the best way. Also it does not tell us the property was modified or not.


Let's try with a different approach , using Property Wrapper. Here we write the management code once and apply it to multiple properties.


Writing the management code will be bit extensive but using it will be a piece of cake  ( by using just the attribute @UserIdentifier)


import Foundation



@propertyWrapper

struct UserIdentifier {

    private var userId: Int

    

    /// Second functionality of Property Wrapper - Projected Value

    var projectedValue: Bool

    

    init() {

        projectedValue = false

        userId = 0

    }

    

    /// First functionality of Property wrapper - Wrapped Value

    var wrappedValue: Int {

        get {

            return userId

        }

        

        set {

            if newValue > 100 {

                userId = 100

                projectedValue = true

            } else {

                userId = newValue

                projectedValue = false

            }

        }

    }

}



struct UserDetails {

    @UserIdentifier var userId: Int

}


        var userDetails = UserDetails()

        userDetails.userId = 2

        print("Projected Value => \(userDetails.$userId)")

        print("Wrapped Value => \(userDetails.userId)")


What is Wrapper Name ?


Wrapper name is "UserIdentifier" .

How to apply Property Wrapper to a Property?

We user the property Wrapper name i.e "UserIdentifier" before a property as an attribute


(@) => attribute

(wrapper name) => UserIdentifier

var userId: Int => property name


Combining all of them together , we apply Property Wrapper to a property.


 @UserIdentifier var userIdInt


Wrapped Value


UserIdentifier structure makes sure's the number it wraps always has number less than or equal to 100.

Any attempt to set a value more than 100, will limit to 100.


How to access wrapped Value?

Accessing the wrapped value is same as accessing the property no special syntax.


So if the structure "UserDetails" uses property wrapper for "userId" , we access it like "userDetails.userId"



Projected Value


Projected value can be of any type , in case of above example we are using it as Bool


The projected value provides additional details of an instance in case any value being set is out of the range i.e more than 100 or less than 100 in the above case.


How to access projected Value?


Simple, just add "$" before the value being accessed. In case of above example it will be userDetails.$userId


In the example above it will print false , when we try to set the value of "userId" to 2.


If we try to set value for example 102. It will print true.


userDetails.userId = 102


It will print true for projected value.



userDetails.$userId 









Comments

Popular posts from this blog

hitTest on iOS to identify the view being hit

CMTimeMakeWithSeconds explained

How to set Custom Section Header in UITableView for ios sdk version greater than 6