swift setter 导致 exc_bad_access

swift setter causing exc_bad_access

下面有一个简单的class

import Foundation

public class UsefulClass: NSObject{
    var test:NSNumber{
        get{return self.test}
        set{
            println(newValue)
            self.test = newValue
        }
    }
    override init() {
        super.init()
        self.test = 5;
    }
}

我在这里初始化它

import UIKit

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        var testClass = UsefulClass()
    }
}

但它导致 xcode 打印出 200 个 5,然后由于 EXC_BAD_ACCESS code = 2 而崩溃。为什么会这样?

Swift 变量默认为合成属性。 在大多数情况下这就足够了(建议选择 Swift 类型)

var test: Int

override init() {
    super.init()
    test = 5
}

如果您需要在设置变量后执行某些操作,请使用

var test: Int {
    didSet{
        println("\(oldValue) - \(newValue)")
    }
}

您的代码通过调用 setter 永久设置变量,该 setter 调用 setter ……

@vadian 在他的回答中提供了解决方案,应该可以解决您的问题。让我解释一下发生了什么。

您创建了一个计算 属性,即没有变量支持的 属性,getter 和 setter 都进行了一些处理,通常在另一个存储属性,以便分别return一个值并设置一个新值。

这是你计算出来的 属性:

var test: NSNumber {
    get { return self.test }
    set {
        println(newValue)
        self.test = newValue
    }
}

查看 getter 实现:

return self.test

它有什么作用?它读取当前实例的 test 属性,然后 returns 它。哪个是test属性?就是这个:

var test: NSNumber {
    get { return self.test }
    set {
        println(newValue)
        self.test = newValue
    }
}

是的,一样属性。你的getter所做的就是递归地无限期地调用自己,直到在运行时发生崩溃。

同样的规则适用于 setter:

self.test = newValue 

它不断调用自身,直到应用程序崩溃。

这是一个无限循环;您的 setter 正在递归调用自身。

var test: NSNumber {
    set {
        test = newValue
    }
}

这编译得很好,Objective-C 程序员可能期望没有循环,因为设置 "backing ivar" 例如 _test 而不是重新调用 setter 方法.

但是 属性-支持实例变量 _ivars 不存在于计算属性的 Swift 中,除非您自己创建它们。