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

时间:2015-09-21 22:39:42

标签: 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 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.
    }
}

此代码将以无限循环运行。具体来说,它会在print("\(viewModel?.price)")中的updateDisplay()didSet的{​​{1}}之间反弹。

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

这是在Swift 2中,虽然我还没有验证它是否在早期的Swift中具有相同的行为。另一个数据点,调用协议上的方法并不会导致调用updateDisplay()

这看起来像是一个Swift错误吗?

2 个答案:

答案 0 :(得分:2)

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

你的willSet属性可能存在问题,你的协议类型里面有一个readonly属性。我做了很多测试,很难找到解决方案。但是,如果你真的需要继续这样做......我认为以下改变可以帮助你

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

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

        set {
            return 
        }
    }
    //...
}

正如您所说......只有在尝试通过viewModel对象直接访问price属性时才会出现问题

我只是在这里提出答案,因为它不适合评论字段大小。

但令人印象深刻......我会尽力找到最终解决方案。 :)

答案 1 :(得分:2)

似乎不仅我在didSet {}中遇到了这个问题。 这个问题有一个开放的雷达:https://openradar.appspot.com/22574299