Имущество и сеттеры
С помощью этого простого класса я получаю предупреждение компилятора
Попытка изменить/получить доступ к 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"
}