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


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

попытка изменить / доступ 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 150

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

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

вы можете настроить заданное значение с помощью обозревателя свойств. Чтобы сделать didSet этого использовать '' вместо 'комплект'.

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

Рассмотрим пример из 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 никогда не изменяет и не возвращает себя в объявлении переменной.

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

var temX : Int? 
var x: Int?{

    set(newX){
       temX = newX
    }

    get{
        return temX
    }
}

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

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

x = 10

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

var newVar = x

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

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

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


правило большого пальца никогда доступ к самому свойству из внутри геттер т. е. 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

в приведенном ниже классе сеттер и геттер применяется к переменной 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 должны быть реализованы.