With this simple class I am getting the compiler warning
Attempting to modify/access
x
within its own setter/getter
and when I use it like this:
var p: point = Point()
p.x = 12
I get an EXC_BAD_ACCESS. How can I do this without explicit backing ivars?
class Point {
var x: Int {
set {
x = newValue * 2 //Error
}
get {
return x / 2 //Error
}
}
// ...
}
This question is related to
swift
properties
compiler-warnings
getter-setter
You are recursively defining x
with x
. As if someone asks you how old are you? And you answer "I am twice my age". Which is meaningless.
You must say I am twice John's age or any other variable but yourself.
computed variables are always dependent on another variable.
The rule of the thumb is never access the property itself from within the getter ie get
. Because that would trigger another get
which would trigger another . . . Don't even print it. Because printing also requires to 'get' the value before it can print it!
struct Person{
var name: String{
get{
print(name) // DON'T do this!!!!
return "as"
}
set{
}
}
}
let p1 = Person()
As that would give the following warning:
Attempting to access 'name' from within it's own getter.
The error looks vague like this:
As an alternative you might want to use didSet
. With didSet
you'll get a hold to the value that is was set before and just got set to. For more see this answer.
Try using this:
var x:Int!
var xTimesTwo:Int {
get {
return x * 2
}
set {
x = newValue / 2
}
}
This is basically Jack Wu's answer, but the difference is that in Jack Wu's answer his x variable is var x: Int
, in mine, my x variable is like this: var x: Int!
, so all I did was make it an optional type.
Setters and getters in Swift apply to computed properties/variables. These properties/variables are not actually stored in memory, but rather computed based on the value of stored properties/variables.
See Apple's Swift documentation on the subject: Swift Variable Declarations.
Setters/getters in Swift are quite different than ObjC. The property becomes a computed property which means it does not have a backing variable such as _x
as it would in ObjC.
In the solution code below you can see the xTimesTwo
does not store anything, but simply computes the result from x
.
See Official docs on computed properties.
The functionality you want might also be Property Observers.
What you need is:
var x: Int
var xTimesTwo: Int {
set {
x = newValue / 2
}
get {
return x * 2
}
}
You can modify other properties within the setter/getters, which is what they are meant for.
I don't know if it is good practice but you can do something like this:
class test_ancestor {
var prop: Int = 0
}
class test: test_ancestor {
override var prop: Int {
get {
return super.prop // reaching ancestor prop
}
set {
super.prop = newValue * 2
}
}
}
var test_instance = test()
test_instance.prop = 10
print(test_instance.prop) // 20
You can customize the set value using property observer. To do this use 'didSet' instead of 'set'.
class Point {
var x: Int {
didSet {
x = x * 2
}
}
...
As for getter ...
class Point {
var doubleX: Int {
get {
return x / 2
}
}
...
To elaborate on GoZoner's answer:
Your real issue here is that you are recursively calling your getter.
var x:Int
{
set
{
x = newValue * 2 // This isn't a problem
}
get {
return x / 2 // Here is your real issue, you are recursively calling
// your x property's getter
}
}
Like the code comment suggests above, you are infinitely calling the x property's getter, which will continue to execute until you get a EXC_BAD_ACCESS code (you can see the spinner in the bottom right corner of your Xcode's playground environment).
Consider the example from the Swift documentation:
struct Point {
var x = 0.0, y = 0.0
}
struct Size {
var width = 0.0, height = 0.0
}
struct AlternativeRect {
var origin = Point()
var size = Size()
var center: Point {
get {
let centerX = origin.x + (size.width / 2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
set {
origin.x = newValue.x - (size.width / 2)
origin.y = newValue.y - (size.height / 2)
}
}
}
Notice how the center computed property never modifies or returns itself in the variable's declaration.
In order to override setter
and getter
for swift variables use the below given code
var temX : Int?
var x: Int?{
set(newX){
temX = newX
}
get{
return temX
}
}
We need to keep the value of variable in a temporary variable, since trying to access the same variable whose getter/setter is being overridden will result in infinite loops.
We can invoke the setter simply like this
x = 10
Getter will be invoked on firing below given line of code
var newVar = x
Here is a theoretical answer. That can be found here
A { get set } property cannot be a constant stored property. It should be a computed property and both get and set should be implemented.
Update for Swift 5.1
As of Swift 5.1 you can now get your variable without using get keyword. For example:
var helloWorld: String {
"Hello World"
}
In the below class setter and getter is applied to variable sideLength
class Triangle: {
var sideLength: Double = 0.0
init(sideLength: Double, name: String) { //initializer method
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 3
}
var perimeter: Double {
get { // getter
return 3.0 * sideLength
}
set(newValue) { //setter
sideLength = newValue / 4.0
}
}
var triangle = Triangle(sideLength: 3.9, name: "a triangle")
print(triangle.perimeter) // invoking getter
triangle.perimeter = 9.9 // invoking setter
Source: Stackoverflow.com