Projecting a Value From a Property Wrapper

Subscribe to my newsletter and never miss my upcoming articles

Hello boys and girls, Leo here.

Today we will explore one great feature of property wrappers, the projected value. It is very useful when you want to have a little more info about the wrapped value. Ex: you have a property wrapper that set a max limit to the int, you can project a boolean value that says if the property was set with more than the max value or less.

Let's code!

You need more information of wrapped values and don't want to the split the logic outside the property context. Ex: You receive a text but the only important info is the first 3 characters and it must be uppercase to show to the user. Also you want to know if it comes bigger than 3 characters from backend or not.

First we need to write our property wrapper:

@propertyWrapper
struct UpperCaseMask {

    private var text: String  //1
    var projectedValue: Bool  //2

    init() {
        self.text = ""
        self.projectedValue = false
    }

    var wrappedValue: String {  //3
        get {return text}
        set {
            if newValue.count > 3 {
                text = newValue.prefix(3).uppercased()
                projectedValue = false
            } else {
                text = newValue.uppercased()
                projectedValue = true
            }
        }
    }
}

On 1 comment mark you see what type will be your wrapper, in this case will be a string. The 2 comment mark explore the concept that we are talking here, you can have another value at the moment you set a new/create value from the property, in this case will be a boolean.

The 3 comment mark show a standard wrappedValue implementation, but as you can see depending on what we set to the property you can specify a projected value. This is useful because you don't need to recalculate that IF statement anywhere else, this way you put some logic on the property itself.

Now you can annotate a property with that and voilá:

struct Home {
    @UpperCaseMask public var homeCode: String

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

}

var home1 = Home(homeCode: "brln123123")

print(home1.$homeCode, home1.homeCode) // 1

home1.homeCode = "can"

print(home1.$homeCode, home1.homeCode) // 1

If you copy and paste into your playgrounds you will this:

Screen Shot 2020-12-30 at 11.14.00.png

You can notice that in the first case we cut the rest of useless info and transformed it into a some "masked" string, and the second case we only upperCase it. To get the projected value we need to put a $ mark before the property name.

The last thing about this feature is, if you access the projected value inside the struct Home, you only use the $ mark and the job is done.

struct Home {
    @UpperCaseMask public var homeCode: String

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

    func getHomeCodeFullDescription() -> String {
        if $homeCode { // < - - - Here 
            return "We just need to uppercase it"
        } else {
            return "We need to cut and uppercase it"
        }
    }
}

And if you test it you get:

var home1 = Home(homeCode: "brln123123")

print(home1.$homeCode, home1.homeCode, home1.getHomeCodeFullDescription())


home1.homeCode = "can"

print(home1.$homeCode, home1.homeCode, home1.getHomeCodeFullDescription())

Screen Shot 2020-12-30 at 11.19.56.png

I hope you enjoy reading this. Any feedback or comment please share below!

Thanks for the reading and... That's all folks!

credit: image

No Comments Yet