swift setter导致exc_bad_access

时间:2015-07-03 14:53:45

标签: swift exc-bad-access setter

我在下面有一个简单的课程

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()
    }
}

但是由于EXC_BAD_ACCESS代码= 2,它导致xcode打印出200 5s然后崩溃。为什么会发生这种情况?

3 个答案:

答案 0 :(得分:11)

@vadian在他的回答中提供了一个解决方案,它可以解决你的问题。我来解释一下发生了什么。

你已经创建了一个计算属性,即一个没有变量支持的属性,而是getter和setter都做了一些处理,通常在另一个存储属性上,以便分别返回一个值并设置一个新值

这是你的计算属性:

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

查看getter实现:

return self.test

它做什么?它读取当前实例的test属性,并返回它。哪个是test属性?就是这个:

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

是的,它是同一个属性。你的getter所做的是以递归方式无限期地调用自身,直到在运行时发生崩溃。

同样的规则适用于setter:

self.test = newValue 

它一直在调用自己,直到应用程序崩溃。

答案 1 :(得分:5)

默认情况下,Swift变量是合成属性。 在大多数情况下这是足够的(建议更喜欢Swift类型)

var test: Int

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

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

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

你的代码通过调用setter调用setter来永久设置变量......

答案 2 :(得分:0)

这是一个无限循环;你的setter递归调用自己。

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

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

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