Search code examples
swiftdesign-patterns

Swift Property Wrappers-Initialization fails with 'cannot convert value of type 'Double' to expected argument type'


I've made myself a playground-example to become familar with Property Wrappers.

Following code:

import Foundation

@propertyWrapper
struct Price {
    private var price: Double
    
    init() {
        self.price = 0.0
    }
    
    var wrappedValue: Double {
        get {
            return self.price
        }
        set {
            if newValue < 0.0 {
                self.price = 0.0
            } else if newValue > 10_000 {
                return
            } else {
                self.price = newValue
            }
        }
    }
}

struct Article {
    var vendor: String
    var name: String
    @Price var price: Double
}

var display = Article(vendor: "Asus", name: "X127", price: 139.0)
/*
 expression failed to parse:
 error: Playground.playground:33:60: error: cannot convert value of type 'Double' to expected argument type 'Price'
 var display = Article(vendor: "Asus", name: "X127", price: 139.0)
 */
print("\(display.vendor) Display costs \(display.price) Euro")

If I use ...

var display = Article(vendor: "Asus", name: "X127")
display.price = 129.99
print("\(display.vendor) Display costs \(display.price) Euro")
// Asus Display costs 129.99 Euro

... then it works fine.

What I'm I doing wrong with the constructor-initialization? What's the correct way to initialize the wrapper property?

What is going wrong within the first example in general?


Solution

  • You need an init that takes a value if you want the first example to work because otherwise the compiler won't know how to assign the value 139.0 to a Price property

    init(wrappedValue: Double) {
        self.price = wrappedValue
    }
    

    Note that the parameter label is wrappedValue to match the required property with the same name to make it possible to assign a default value.

    And you also need to remove the existing init without parameters. This init is also the reason why your second example works since it gets called when there is no value for the price argument in the Article constructor meaning it works like a default value.