Tin Challenge Solution

Here’s my current solution. I wasn’t sure how to set/update totalValue variable as a computed property, so I set its value in the store(_ asset:) method which was the only way I could access the new values.

Is there a way to include the original values of each asset? For example, if the Rare Coin asset has an initial value of 1_000.0, and I updated it by 137, then the output should say "New total value: optional(1137.0).

class Vault {
    let number: Int
    
    private(set) var assets = [Asset]()
    
    var totalValue: Double = 0
    
    init(number: Int) {
        self.number = number
    }
    
    deinit {
        print("\(self) is being deallocated")
    }
    
    func store(_ asset: Asset) {
        asset.container = self
        asset.changeHandler = { [weak self] (change) in
            self?.totalValue += change
            print("An asset has changed value by \(change). New total value: \(String(describing: self?.totalValue))")
        }
        
        assets.append(asset)
    }
}

extension Vault: CustomStringConvertible {
    var description: String {
        return "Vault(\(number))"
    }
}
class Simulation {
    func run() {
        let vault13 = Vault(number: 13)
        print("Created \(vault13)")
        
        let coin: Asset = Asset(name: "Rare Coin", value: 1_000.0)
        let gem: Asset = Asset(name: "Big Diamond", value: 5_000.0)
        let poem: Asset = Asset(name: "Magnum Opus", value: 0.0)
        
        vault13.store(coin)
        vault13.store(gem)
        
        print("Created some assets: \([coin, gem, poem])")
        
        coin.value += 137   // New total value: Optional(137.0)
        gem.value += 50    // New total value: Optional(187.0)
    }
}

The idea behind a computed property is you don’t set its value at all, instead you calculate it on the fly each time it is needed. So your definition of totalValue should be something like:

    var totalValue: Double {
        // add code here to calculate & return the total value of all assets in the container
    }

and store doesn’t set totalValue. Refer back to chapter 16 if you need a refresher on computed properties.

If you want store to print out the old totalValue, the best way I can see to do that would be to subtract change from totalValue:

    func store(_ asset: Asset) {
        asset.container = self
        asset.changeHandler = { [weak self] (change) in
            print("""
                An asset has changed value by \(change). \
                Old total value: \(self!.totalValue - change). \
                New total value: \(String(describing: self?.totalValue))
                """)
        }
        assets.append(asset)
    }

(This probably isn’t ideal since I’m force-unwrapping self but I couldn’t figure out a better syntax.)

Since changeHandler is being called on didSet there’s no way to directly access the old value of totalValue; it has already changed (because the value of one of the underlying Assets has already changed). You could possibly change Asset to call changeHandler on willSet but then you’d just have to calculate the new totalValue instead of the old one, so you’re not really better off.

Edit: If you want to print out the old value of the asset rather than the vault, I’d add code to didSet to print that.

Thanks for the advice regarding computed properties which also answered my question on why the original values for each asset wasn’t being included when printing the updated asset values.

Here’s my updated solution for the tin challenge

    var totalValue: Double {
        var result: Double = 0
        for asset in assets {
            result += asset.value
        }
        
        return result
    }