简体   繁体   English

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

[英]didSet called when getting a property declared as a protocol

Here's some code: 这是一些代码:

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.
    }
}

This code will run in an infinite loop. 此代码将在无限循环中运行。 Specifically, it bounces between print("\\(viewModel?.price)") in updateDisplay() and the didSet for viewModel . 具体来说,它在updateDisplay() print("\\(viewModel?.price)") updateDisplay()didSetviewModel

If you change viewModel 's type to ViewModel directly (skipping the protocol), the infinite loop disappears. 如果直接将viewModel的类型更改为ViewModel (跳过协议),则无限循环消失。 Alternatively, if you unwrap viewModel in updateDisplay() before using it the infinite loop also disappears. 或者,如果在使用updateDisplay()之前解开viewModel ,则无限循环也会消失。

This is in Swift 2, although I haven't verified if it has the same behavior in earlier Swift. 这是在Swift 2中,虽然我还没有验证它是否在早期的Swift中具有相同的行为。 One other data point, calling methods on the protocol doesn't cause a call to didSet . 另一个数据点,调用协议上的方法不会导致调用didSet

Does this look like a Swift bug to you? 这看起来像是一个Swift bug吗?

It's a very impressive case. 这是一个非常令人印象深刻的案例。

It maybe a problem with your willSet attribute with your protocol type having a readonly attribute inside. 你的willSet属性可能是一个问题,你的协议类型里面有一个readonly属性。 I made a lots of tests and it's being very hard to find a solutions. 我做了很多测试,很难找到解决方案。 But, if you really need to keep going in this way... I think the follow change can help you 但是,如果你真的需要继续这样做......我认为以下改变可以帮助你

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

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

        set {
            return 
        }
    }
    //...
}

As you said... The problem only happens when try to access directly the price attribute via viewModel object 如你所说......只有在尝试通过viewModel对象直接访问price属性时才会出现问题

I just put my answer here, cause it didn't fit in comment field size. 我只是把我的答案放在这里,因为它不适合评论字段大小。

But is very impressive... I will try to find a final solution. 但是非常令人印象深刻......我会尽力找到最终解决方案。 :) :)

It seems that not only I have this problem with didSet{}. 似乎不仅我有didSet {}的这个问题。 There is open radar for this issue: https://openradar.appspot.com/22574299 这个问题有一个开放的雷达: https//openradar.appspot.com/22574299

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM