Геттеры и сеттеры свойств

С этим простым классом я получаю компилятор предупреждение

попытка изменить / доступ x в своем собственном сеттере / геттере

и когда я использую его так:

var p: point = Point()
p.x = 12

Я получаю EXC_BAD_ACCESS. Как я могу это сделать без явной поддержки ivars?

class Point {

    var x: Int {
        set {
            x = newValue * 2 //Error
        }
        get {
            return x / 2 //Error
        }
    }
    // ...
}

10 ответов


сеттеры и геттеры применить к computed properties; такие свойства не имеют хранилища в экземпляре - значение из геттера должно вычисляться из других свойств экземпляра. В вашем случае, нет x будет назначен.

явно: "как я могу это сделать без явной поддержки ivars". Вы не можете - вам понадобится что-то для резервного копирования вычисляемого свойства. Попробуйте это:

class Point {
  private var _x: Int = 0             // _x -> backingX
  var x: Int {
    set { _x = 2 * newValue }
    get { return _x / 2 }
  }
}

в частности, в Swift REPL:

 15> var pt = Point()
pt: Point = {
  _x = 0
}
 16> pt.x = 10
 17> pt
$R3: Point = {
  _x = 20
}
 18> pt.x
$R4: Int = 10

сеттеры / геттеры в Swift сильно отличаются от ObjC. Свойство становится вычисляемое свойство что означает это не имеют переменную поддержки, такую как _x как и в ObjC.

в коде решения ниже вы можете увидеть xTimesTwo тут не хранить что-нибудь, а просто вычисляет результат x.

посмотреть официальные документы по вычисляемым свойствам.

в функциональность, которую вы хотите, также может быть Наблюдатели За Недвижимостью.

что нужно:

var x:Int

var xTimesTwo:Int {
    set {
       x = newValue / 2
    }
    get {
        return x * 2
    }
}

вы можете изменить другие свойства в сеттере / геттерах, для чего они предназначены.


вы можете настроить заданное значение с помощью Property observer. Для этого используйте 'didSet' вместо 'set'.

class Point {

var x:Int {
    didSet {
        x = x * 2
    }
}
...

Что касается геттера ...

class Point {

var doubleX: Int {
    get {
        return x / 2
    }
}
...

подробнее об ответе Гозонера:

ваша реальная проблема здесь в том, что вы рекурсивно вызываете свой геттер.

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

Как следует из комментария кода выше, вы бесконечно вызываете геттер свойства x, который будет продолжать выполняться, пока вы не получите код EXC_BAD_ACCESS (вы можете увидеть счетчик в правом нижнем углу игровой площадки вашего Xcode).

Рассмотрим пример из Swift документация:

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

обратите внимание, что свойство center computed никогда не изменяет и не возвращает себя в объявлении переменной.


для того, чтобы переопределить setter и getter для переменных swift используйте приведенный ниже код

var temX : Int? 
var x: Int?{

    set(newX){
       temX = newX
    }

    get{
        return temX
    }
}

нам нужно сохранить значение переменной во временной переменной, так как попытка доступа к той же переменной, геттер / сеттер которой переопределяется, приведет к бесконечным циклам.

мы можем вызвать сеттера просто так

x = 10

Getter будет вызываться при стрельбе ниже заданной строки кода

var newVar = x

вы рекурсивно определение x С x. Как будто кто-то спрашивает, Сколько тебе лет? И вы отвечаете:"Я вдвое старше". Что бессмысленно.

вы должны сказать, что я вдвое старше Джона или любой другой переменной но себя.

вычисляемые переменные всегда зависят от другой переменной.


правило большого пальца никогда доступ к самому свойству из внутри геттер ie get. Потому что это вызовет другой get который вызовет другой . . . Даже не печатай. Потому что печать также требует "получить" значение, прежде чем он может напечатать его!

struct Person{
    var name: String{
        get{
            print(name) // DON'T do this!!!!
            return "as"
        }
        set{
        }
    }
}

let p1 = Person()

как это даст следующее предупреждение:

попытка получить доступ к "имени" изнутри собственного геттера.

ошибка выглядит расплывчато, как это:

enter image description here

в качестве альтернативы вы можете использовать didSet. С didSet вы получите удержание значения, которое было установлено раньше и только что было установлено. Подробнее ответ.


попробуйте использовать этот:

var x:Int!

var xTimesTwo:Int {
    get {
        return x * 2
    }
    set {
        x = newValue / 2
    }
}

это в основном ответ Джека Ву, но разница в том, что в ответе Джека Ву его переменная x var x: Int, в моем, моя переменная x выглядит так:var x: Int!, поэтому все, что я сделал, это сделать его необязательным типом.


Обновление: Swift 4

в приведенном ниже классе setter и getter применяется к переменной 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 { //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

сеттеры и геттеры в Swift применяются к вычисляемым свойствам / переменным. Эти свойства / переменные фактически не хранятся в памяти, а вычисляются на основе значения сохраненных свойств/переменных.

см. документацию Apple Swift по этому вопросу:Swift Объявления Переменных.


вот теоретический ответ. Это можно найти здесь

свойство { get set } не может быть постоянным хранимым свойством. Это должно быть вычисляемое свойство, и get и set должны быть реализованы.