Имущество и сеттеры

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

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

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

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

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

class Point {

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

Ответ 1

Setters и Getters относятся к computed properties; такие свойства не хранятся в экземпляре - значение из геттера предназначено для вычисления из других свойств экземпляра. В вашем случае нет назначенного x.

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

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

Ответ 2

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

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

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

Функцией, которую вы хотите, также могут быть наблюдатели свойств.

Что вам нужно, это:

var x: Int

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

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

Ответ 3

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

class Point {

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

Что касается добытчика...

class Point {

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

Ответ 4

Чтобы уточнить ответ GoZoner:

Ваша настоящая проблема заключается в том, что вы рекурсивно называете своего получателя.

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

Как и предыдущий комментарий коментария, вы бесконечно вызываете свойство get 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)
        }
    }
}

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

Ответ 5

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

var temX : Int? 
var x: Int?{

    set(newX){
       temX = newX
    }

    get{
        return temX
    }
}

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

Мы можем вызвать установщик просто так:

x = 10

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

var newVar = x

Ответ 6

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

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

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


Правило большого пальца никогда не получает доступ к самому свойству из getter 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 вы получите didSet к значению, которое было установлено ранее и только что настроено. Подробнее см. Этот ответ.

Ответ 7

Обновление: 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")

Getter

print(triangle.perimeter) // invoking getter

сеттер

triangle.perimeter = 9.9 // invoking setter

Ответ 8

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

var x:Int!

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

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

Ответ 9

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

См. документацию Apple Swift по теме: Swift Variable Declarations.

Ответ 10

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

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

Ответ 11

Обновление для Swift 5.1

Начиная с Swift 5.1, теперь вы можете получить свою переменную без использования ключевого слова get. Например:

var helloWorld: String {
"Hello World"
}