问题
I have a simple class below
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;
}
}
and I'm initializing it here
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var testClass = UsefulClass()
}
}
But it results in xcode printing out 200 5s and then crashing due to EXC_BAD_ACCESS code = 2. Why does this happen?
回答1:
@vadian has provided a solution in his answer, which should fix your problem. Let me just explain what's happening.
You have created a computed property, i.e. a property which is not backed by a variable, instead both the getter and the setter do some processing, usually on another stored property, in order to respectively return a value and set a new value.
This is your computed property:
var test: NSNumber {
get { return self.test }
set {
println(newValue)
self.test = newValue
}
}
Look at the getter implementation:
return self.test
What does it do? It reads the test
property of the current instance, and returns it. Which is the test
property? It's this one:
var test: NSNumber {
get { return self.test }
set {
println(newValue)
self.test = newValue
}
}
Yes, it's the same property. What your getter does is to recursively and indefinitely calling itself, until a crash happen at runtime.
The same rule applies to the setter:
self.test = newValue
it keeps invoking itself, until the app crashes.
回答2:
Swift variables are synthesized properties by default. In the most cases this is sufficient (it's recommended to prefer Swift types)
var test: Int
override init() {
super.init()
test = 5
}
If you need to do something after a variable is set, use
var test: Int {
didSet{
println("\(oldValue) - \(newValue)")
}
}
your code sets the variable permanently by calling the setter which calls the setter which …
回答3:
It's an infinite loop; your setter is recursively calling itself.
var test: NSNumber {
set {
test = newValue
}
}
This compiles fine, and an Objective-C programmer might expect no loop due to instead setting a "backing ivar" such as _test
rather than re-calling the setter method.
But property-backing instance variable _ivars
do not exist in Swift for computed properties unless you create them yourself.
来源:https://stackoverflow.com/questions/31209615/swift-setter-causing-exc-bad-access