Initialise property wrapper with dynamic values in Swift 5
Asked Answered
T

2

5

Scenario:

  1. I want to have different types of Bonds which has a minimum value, flexi interest current bond worth(calculated on basis of some logic) and bond growth prediction.

  2. Whenever bond value goes more than minimum value, then the growth prediction becomes appreciating and depreciating in vice versa.

  3. I can have multiple bonds with their own set of values.

I am trying to use property wrappers for the same so that I do not replicate the same behaviour for every bond:

 @propertyWrapper
struct BondValue {
    private var bondCurrentWorth: Int
    private var minimumValue: Int
    private var flexiInterest: Int
    
    var projectedValue: BondGrowth = .appreciating // The projected value projects the growth for the bond
    
    var wrappedValue: Int {

        get {
            return bondCurrentWorth
        }
        
        set {
            bondCurrentWorth = newValue + (newValue * flexiInterest/100)
            projectedValue = bondCurrentWorth < minimumValue ? .depriciating : .appreciating
        } 
 }
    
    init(wrappedValue: Int = 0, minimumValue: Int, flexiInterest: Int, value: Int) {
        self.minimumValue = minimumValue
        self.flexiInterest = flexiInterest
        self.bondCurrentWorth = value
    }
}

Now for creating any bond, I do:

struct FoodBond {
    var bondName: String
    @BondValue(minimumValue: 200, flexiInterest: 30, value: 200) var value = 30
    
    init(bondName: String, minimumValue: Int, flexiInterest: Int, value: Int) {
        self.bondName = bondName
    }
}

Problem statement:

  • I am not able to initialize the bondvalue with dynamic values.

Possible workaround: I would use the same approach as a normal struct in the below implementation. Though this way of using property wrappers is also specified in the docs, but I would lose the syntactic flavor of the property wrappers.

You could write code that uses the behavior of a property wrapper, without taking advantage of the special attribute syntax. For example, here’s a version of SmallRectangle from the previous code listing that wraps its properties in the TwelveOrLess structure explicitly, instead of writing @TwelveOrLess as an attribute

@propertyWrapper
struct BondValue {
    private (set) var bondCurrentWorth: Int
    private (set) var minimumValue: Int
    private (set) var flexiInterest: Int
    
    var projectedValue: BondGrowth = .appreciating // The projected value projects the growth for the bond
    
    var wrappedValue: Int { .... }
    
    init(wrappedValue: Int = 0, minimumValue: Int, flexiInterest: Int, value: Int) { ... }
}

struct FoodBond {
    var bondName: String
    var value = BondValue(minimumValue: 0, flexiInterest: 0, value: 0) // Provide a default value
    
    init(bondName: String, minimumValue: Int, flexiInterest: Int, value: Int) {
        self.bondName = bondName
        self.value = BondValue(minimumValue: minimumValue, flexiInterest: flexiInterest, value: value)
    }
}

var foodBond = FoodBond(bondName: "Food Bond", minimumValue: 200, flexiInterest: 10, value: 200)
print("Initial bond current worth - \(foodBond.value.bondCurrentWorth)")
print("Bond growth - \(foodBond.value.projectedValue)")

Any suggestions will be really helpful.

Thynne answered 31/10, 2019 at 5:39 Comment(0)
T
5

Referring to the section Memberwise Initialisers from Swift proposal doc for property wrappers:

Instance properties that have a property wrapper will have a corresponding parameter in the memberwise initializer, whose type will either be the original property type or the wrapper type, depending on the wrapper type and the initial value (if provided).

Solution:

struct FoodBond {
    var bondName: String

    @BondValue(minimumValue: 0, flexiInterest: 0, value: 0) var bondValue = 0

    init(bondName: String, minimumValue: Int, flexiInterest: Int, value: Int) {
        self.bondName = bondName
        _bondValue = BondValue(minimumValue: minimumValue, flexiInterest: flexiInterest, value: value)
    }
}
Thynne answered 1/11, 2019 at 0:40 Comment(0)
W
1

You can use the property wrapper without params and give it the type of the wrapped value, then create it in the init with your params:

struct FoodBond {
    var bondName: String

    @BondValue var bondValue : Int

    init(bondName: String, minimumValue: Int, flexiInterest: Int, value: Int) {
        self.bondName = bondName
        _bondValue = BondValue(minimumValue: minimumValue, flexiInterest: flexiInterest, value: value)
    }
}
Wendy answered 3/10, 2020 at 16:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.