この単純なクラスで私はコンパイラを手に入れています warning
自身のセッター/ゲッター内で
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
}
}
// ...
}
セッターとゲッターはcomputed properties
に適用されます。そのようなプロパティはインスタンス内にストレージを持っていません - ゲッターからの値は他のインスタンスプロパティから計算されることを意味します。あなたの場合、代入するx
はありません。
明示的に: "明示的なivarsの裏付けなしにこれを行うにはどうすればよいですか"。計算プロパティをバックアップするために something は必要ありません。これを試して:
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とはまったく異なります。プロパティは、計算済みプロパティになります。つまり、ObjCの場合のように、_x
などのバッキング変数はありませんnot。
以下のソリューションコードでは、xTimesTwo
が何かを保存するnotが、単に computes x
の結果を保存することがわかります。
計算されたプロパティの公式ドキュメント を参照してください。
また、必要な機能は Property Observers かもしれません。
必要なのは:
var x:Int
var xTimesTwo:Int {
set {
x = newValue / 2
}
get {
return x * 2
}
}
セッター/ゲッター内の他のプロパティを変更できます。
プロパティオブザーバを使用して設定値をカスタマイズできます。これを行うには、 'set'ではなく 'didSet'を使用してください。
class Point {
var x:Int {
didSet {
x = x * 2
}
}
...
ゲッターは・・・.
class Point {
var doubleX: Int {
get {
return x / 2
}
}
...
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's getter
}
}
上記のコードコメントが示すように、あなたは無限にxプロパティのgetterを呼び出しています。そしてそれはあなたが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)
}
}
}
中央の計算プロパティが、変数の宣言内で自分自身を変更したり返したりしないことに注意してください。
Swift変数のsetter
とgetter
をオーバーライドするには、以下のコードを使用してください。
var temX : Int?
var x: Int?{
set(newX){
temX = newX
}
get{
return temX
}
}
Getter/setterがオーバーライドされているのと同じ変数にアクセスしようとすると、無限ループが発生するため、variableの値を一時変数に保持する必要があります。
このようにセッターを呼び出すことができます
x = 10
Getterは与えられたコード行の下で起動すると呼び出されます
var newVar = x
x
name__でx
name__を定義している再帰的です。誰かがあなたに何歳かと尋ねるように?そして、あなたは「私は私の年齢の2倍です」と答えます。これは無意味です。
私はジョンの年齢の2倍または他の変数but自分であると言わなければなりません。
計算された変数は常に別の変数に依存しています。
経験則は、neverゲッター、つまりget
name__内からwithinからプロパティ自体にアクセスします。それは別のをトリガーする別のget
name__をトリガーするためです。 。 。それも印刷しないでください。印刷では、印刷する前に値を「取得」する必要があるためです!
struct Person{
var name: String{
get{
print(name) // DON'T do this!!!!
return "as"
}
set{
}
}
}
let p1 = Person()
次の警告が表示されます。
独自のゲッター内から「名前」にアクセスしようとしています。
エラーは次のようにあいまいに見えます。
別の方法として、didSet
name__を使用することもできます。 didSet
name__を使用すると、以前に設定されたばかりの値が保持されます。詳細については、 this answer を参照してください。
以下のクラスでは、セッターとゲッターは変数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
これを使ってみてください。
var x:Int!
var xTimesTwo:Int {
get {
return x * 2
}
set {
x = newValue / 2
}
}
これは基本的にはJack Wuの答えですが、違いはJack Wuの答えでは彼のx変数はvar x: Int
であり、私のx変数はvar x: Int!
のようなものです。
Swift 5.1の更新
Swift 5.1の時点で、getキーワードを使用せずに変数を取得できるようになりました。例えば:
var helloWorld: String {
"Hello World"
}
Swiftのセッターとゲッターは、計算されたプロパティ/変数に適用されます。これらのプロパティ/変数は実際にはメモリに格納されているのではなく、格納されているプロパティ/変数の値に基づいて計算されています。
この件に関してはAppleのSwiftのドキュメントを見てください: Swift Variable Declarations 。
これが理論的な答えです。それが見つかります ここ
{get set}プロパティを定数の保存プロパティにすることはできません。それは計算されたプロパティであるべきで、getとsetの両方が実装されるべきです。