【问题标题】:Computed Property is duplicating计算属性重复
【发布时间】:2021-07-31 02:57:03
【问题描述】:
class test {
    
    var _x : [Int]?
    var x : [Int]? {
        get {
            return _x
        }
        set{
            if let value = newValue {
                for each in value {
                    _x!.append(each)
                }
            }
        }
    }
    
    init() {
        _x = [Int]()
        x?.append(3)
    }
    
    
}

var classTest = test()
classTest.x?.append(2)
print(classTest.x)

我得到 [3,3,2] 而不是 [3,2] 为什么我不明白?预期的行为是我们在 Initializer 中将 3 附加到 x,然后再附加 2。

编辑

感谢您的所有回复,尽管我仍然没有掌握这种行为的窍门。

所以当我做.append(2) 时,swift 会获取_x 的现有值,即3,然后将2 附加到它,然后将newValue 设置为[3,2]。我认为newValue 仅表示新值,即刚刚分配给计算属性的值。

【问题讨论】:

  • 试试我的代码,看看会发生什么......
  • @dev_ios999 那么既然newValue 具有先前的值和附加的值,并且您为每个循环执行一次,那么预期的结果肯定是所有内容都会再次附加吗?如果您只想附加最新值,那么不要为每个循环执行一次,而只选择最后一个? (或者更好的是像建议的那样替换整个东西。)
  • newValue 是新的 array,它不仅仅是附加的值。如果一个值被删除,它会如何工作?
  • “为什么 .append(2) 应该将 newValue 设置为 2,但它也将现有值设置为 3”。好吧,这种行为是最有意义的。考虑要删除元素的情况 - remove(at: 0)。您正在通过这样做设置数组,因此将调用 setter,但是根据 your 逻辑,这次newValue 会是什么?显然,将newValue 设置为属性的整个新数组更有意义。
  • 非常次要且不相关的观察。类型名称(例如结构、类等),总是首字母大写。所以,你可能想要Test 而不是test 作为类名。

标签: ios swift computed-properties


【解决方案1】:

重复的原因是您在遍历并重新填充 newValue 之前没有清除内部变量。因此,您只是将现有数组添加到具有新值的同一个现有数组中。您可以在遍历之前清除 _x 或将 newValue 应用于 _x:

class test {
    
    var _x : [Int]?
    var x : [Int]? {
        get {
            return _x
        }
        set{
            _x = newValue

            // or

            _x = []
            if let value = newValue {
                for each in value {
                    _x!.append(each)
                }
            }
        }
    }
    
    init() {
        _x = [Int]()
        x?.append(3)
    }
    
    
}

var classTest = test()
classTest.x?.append(2)
print(classTest.x)

【讨论】:

  • 是的,我知道了,但为什么响应 .append(2) newValue 已经获得现有值 (3) 并附加 (2) 到它。 newValue 的值不应该是 2 吗?
  • @dev_ios999 不,不应该。因为 getter 中的 newValue 已经收到完整的值(添加了新元素)。方法.append() 更改现有数组,并使用所有元素(包括新元素)重新创建数组_x。它相当于_x = _x + [3]。我回答了你的问题了吗?
【解决方案2】:

append 执行 get 来接收数组属性的副本,然后将新值附加到该副本,然后使用新数组调用 set

所以类可以写成

class Test {
    private var _x : [Int]?
    var x : [Int]? {
        get {
            return _x
        }
        set {
            _x = newValue
        }
    }

    init() {
        _x = [Int]()
        x?.append(3)
    }
}

考虑以下示例,我将print("Getting") 添加到get 子句

var classTest = Test()

classTest.x?.append(2)
print(classTest.x)
classTest.x = [1,4]
print(classTest.x)
classTest.x?.remove(at: 0)
print(classTest.x)

获取
获取
可选([3, 2])
获取
可选([1, 4])
获取
获取
可选([4])

如您所见,它正在为print 命令以及appendremove 命令打印“Getting”,因为它需要修改一个副本

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-28
    • 2018-11-24
    • 1970-01-01
    • 2020-11-27
    • 2020-12-10
    • 1970-01-01
    • 2019-10-25
    • 1970-01-01
    相关资源
    最近更新 更多