Swift 获取声明为协议的属性时调用了didSet

Swift 获取声明为协议的属性时调用了didSet,swift,protocols,swift2,optional,Swift,Protocols,Swift2,Optional,下面是一些代码: import UIKit protocol ViewModelProtocol { var price: String { get } } class ViewModel: ViewModelProtocol { var price: String { return "$420" } } class ViewController: UIViewController { // If you change the type t

下面是一些代码:

import UIKit

protocol ViewModelProtocol {
    var price: String { get }
}

class ViewModel: ViewModelProtocol {
    var price: String {
        return "$420"
    }
}

class ViewController: UIViewController {

    // If you change the type to ViewModel directly, no infinite loop
    var viewModel: ViewModelProtocol? = nil {
        didSet {
            print("viewModel didSet called")
            updateDisplay()
        }
    }

    required init?(coder aDecoder: NSCoder) {
        viewModel = ViewModel()
        super.init(coder: aDecoder)
        updateDisplay()
    }

    func updateDisplay() {
        print("In updateDisplay()")
        print("\(viewModel?.price)")
        // if you access the viewModel like this, no infinite loop
        // if let v = viewModel {
        //     print("\(v.price)")
        // }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}
此代码将在无限循环中运行。具体来说,它在
updateDisplay()
中的
print(\(viewModel?.price)
viewModel
didSet
之间跳跃

如果直接将
viewModel
的类型更改为
viewModel
(跳过协议),无限循环将消失。或者,如果在使用前在
updateDisplay()
中展开
viewModel
,无限循环也会消失

这是在Swift 2中,尽管我还没有验证它是否与早期Swift中的行为相同。另一个数据点是,调用协议上的方法不会导致调用
didSet


这对你来说像是一个快速的错误吗?

这是一个非常令人印象深刻的案例

这可能是由于协议类型中包含只读属性而导致的willSet属性出现问题。我做了很多测试,很难找到解决方案。但是,如果你真的需要继续这样下去。。。我认为下面的变化可以帮助你

protocol ViewModelProtocol {
    var price: String { get set }
}

class ViewModel: ViewModelProtocol {
    var price: String  {
        get {
            return "$420"
        }

        set {
            return 
        }
    }
    //...
}
正如你所说。。。仅当尝试通过viewModel对象直接访问price属性时,才会出现此问题

我只是把我的答案放在这里,因为它不适合评论字段的大小


但是非常令人印象深刻。。。我将设法找到最终的解决办法。:)

似乎不仅我对didSet{}有这个问题。 对于这个问题,有一个公开的雷达: