Геттеры и сеттеры свойств
С помощью этого простого класса я получаю компилятор предупреждение
попытка изменить / доступ
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 } }
вы можете изменить другие свойства в сеттере / геттерах, для чего они предназначены.
вы можете настроить заданное значение с помощью обозревателя свойств. Чтобы сделать 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()
как это даст следующее предупреждение:
попытка получить доступ к " имя " изнутри это собственный геттер.
ошибка выглядит расплывчато, как это:
в качестве альтернативы вы можете использовать
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 должны быть реализованы.