속성 게터와 세터


195

이 간단한 클래스를 사용하면 컴파일러 경고가 나타납니다.

x자체 setter / getter 내 에서 수정 / 액세스 시도

내가 이것을 이렇게 사용할 때 :

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

EXC_BAD_ACCESS를 얻습니다. ivar을 명시 적으로 백업하지 않고 어떻게해야합니까?

class Point {

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

1
그렇게하면 컴파일러에 추가 부하가 걸리고 CPU를 적극적으로 소비합니다. 방금 했어 : | . 이것은 내가 만드는 오류였습니다. (저는 운동장을 사용하고있었습니다)
Honey,

이 문제는 사용하는 대신, 혼란 set사용 싶은 didSet. Swift에서 Objective-C 또는 다른 언어를 구현할 때 속성이 다르게 동작합니다 set. 참고 항목 @jack에서 아래에 대답 하고 didSet@cSquirrel에서
폴 솔트

답변:


232

세터와 게터는 다음에 적용됩니다 computed properties. 이러한 속성에는 인스턴스에 스토리지가 없습니다. 게터의 값은 다른 인스턴스 속성에서 계산됩니다. 귀하의 경우 x할당 할 필요 가 없습니다 .

명시 적으로 : "명백한 ivar을 지원하지 않고 어떻게해야합니까?" 할 수 없습니다- 계산 된 속성을 백업하기 위해 무언가 가 필요 합니다. 이 시도:

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

106

스위프트의 세터 / 게터는 ObjC와 매우 다릅니다. 이 속성은 계산 된 속성이되므로 ObjC에서 와 같이 지원 변수 가 없습니다_x .

아래 솔루션 코드에서는 아무것도 저장 xTimesTwo하지 않고 단순히 결과를 계산 하는 것을 볼 수 있습니다 x.

계산 된 속성에 대한 공식 문서를 참조하십시오 .

원하는 기능은 속성 관찰자 일 수도 있습니다 .

필요한 것은 :

var x: Int

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

setter / getter 내에서 다른 속성을 수정할 수 있습니다.


1
그렇습니다, 그것은 제가 문서에서 읽고있는 것입니다. 속성 섹션을 건너 뛰었고이 문제를 해결할 방법이없는 것 같습니다.
Atomix

그렇습니다. 실제로 원한다면 첫 번째 인스턴스를 "되돌리려면"다른 인스턴스 변수가 필요합니다. 그러나 세터는이 목적을위한 것이 아닙니다. 아마도 이것으로 달성하려는 것을 다시 생각해야합니다.
Jack

5
당신은 사용할 수 있습니다 didSet당신이 그것을 설정 후 즉시 값을 변경 할 수있다. 그래도 얻을 수있는 것은 ...
ObjectiveCsam

1
참고 : 입력이 잘못되어 값을 되돌리려면에서로 x다시 설정해야 oldValue합니다 didSet. 이러한 행동의 변화는 Objective-C 속성에서 오는 매우 혼란 스럽습니다.
Paul Solt

105

속성 관찰기를 사용하여 설정 값을 사용자 정의 할 수 있습니다. 이렇게하려면 'set'대신 'didSet'을 사용하십시오.

class Point {

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

게터에 관해서는 ...

class Point {

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

x이 패턴에서 어떻게 기본값으로 초기화 할 수 있습니까?
i_am_jorf

3
나는 그것이 될 것입니다 : var x: Int = 0 { didSet { ....
i_am_jorf

31

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

중심 계산 속성이 변수 선언에서 어떻게 수정되거나 자신을 반환하지 않는지 확인하십시오.


엄지 손가락의 규칙은 getter 에서 속성 자체에 절대 액세스 하지 않습니다 . 왜냐하면 다른 트리거 될 것이고 다른 트리거 될 것이다. . . 인쇄조차하지 마십시오. 인쇄는 인쇄하기 전에 값을 '얻어야'하기 때문에 필요합니다! getget
Honey

19

재정의 setter하고 getter신속한 변수를 위해 아래 주어진 코드를 사용하십시오.

var temX : Int? 
var x: Int?{

    set(newX){
       temX = newX
    }

    get{
        return temX
    }
}

getter / setter가 재정의되는 동일한 변수에 액세스하려고하면 무한 루프가 발생하므로 변수 값을 임시 변수에 유지해야합니다.

이렇게 간단하게 setter를 호출 할 수 있습니다

x = 10

주어진 코드 줄 아래에서 Getter가 실행됩니다.

var newVar = x

8

재귀 적으로 정의 x하고 x있습니다. 누군가가 당신에게 몇 살을 묻는 것처럼? 그리고 당신은 "나의 나이 두 배입니다"라고 대답합니다. 의미가 없습니다.

당신은 내가 두 번 존의 연령이나 다른 변수입니다 말을해야 하지만 자신.

계산 된 변수는 항상 다른 변수에 의존합니다.


엄지 손가락의 규칙은 getter 에서 속성 자체에 절대 액세스 하지 않습니다 . 왜냐하면 다른 트리거 될 것이고 다른 트리거 될 것이다. . . 인쇄조차하지 마십시오. 인쇄는 인쇄하기 전에 값을 '얻어야'하기 때문에 필요합니다!getget

struct Person{
    var name: String{
        get{
            print(name) // DON'T do this!!!!
            return "as"
        }
        set{
        }
    }
}

let p1 = Person()

따라서 다음과 같은 경고가 나타납니다.

자체 getter 내에서 'name'에 액세스하려고합니다.

오류는 다음과 같이 모호합니다.

여기에 이미지 설명을 입력하십시오

대안으로 사용하고 싶을 수도 있습니다 didSet. 함께 didSet하기 전에 설정되고 단지로 설정되었다 값에 보류를 얻을 것이다. 자세한 내용은 이 답변을 참조하십시오 .


8

업데이트 : 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(newValue) { //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

6

이것을 사용해보십시오 :

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!그래서 내가 한 모든 것은 선택적인 유형이었습니다.


1

Swift 5.1 업데이트

Swift 5.1부터는 get 키워드 를 사용하지 않고도 변수를 얻을 수 있습니다. 예를 들면 다음과 같습니다.

var helloWorld: String {
"Hello World"
}

helloWorld = "macWorld" 를 변경하려고하면 값에 할당 할 수 없습니다 : 'helloWorld'는 가져 오기 전용 속성 오류입니다.
McDonal_11

새 값을 할당 할 수 있습니까? 아니면 아니?
McDonal_11

나는 그것이 가능하다고 생각하지 않습니다.
atalayasa

문자 그대로 var helloWorld : String { "Hello World"}, helloWorld : String = "Hello World"가 동일합니까?
McDonal_11

예, 그렇게 생각합니다.
atalayasa

0

Swift의 세터 및 게터는 계산 된 속성 / 변수에 적용됩니다. 이러한 속성 / 변수는 실제로 메모리에 저장되는 것이 아니라 저장된 속성 / 변수의 값을 기반으로 계산됩니다.

주제에 대한 Apple의 Swift 설명서를 참조하십시오 : Swift Variable Declarations .


0

이론적 인 답변이 있습니다. 여기 에서 찾을 수 있습니다

{get set} 속성은 상수 저장 속성 일 수 없습니다. 계산 된 속성이어야하며 get과 set을 모두 구현해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.