티스토리 뷰

반응형

안녕하세요 :) Zedd입니다.

저번 < Properties - Stored Property(저장 프로퍼티) >글에 이어서 연산 프로퍼티 글을 써볼게요!

위 글을 반드시!!!!!!!읽고오셔야 연산 프로퍼티 글도 이해가 잘 되실거에요 :)

그럼 시작할게요 ~.~

 

 

Computed Property(연산 프로퍼티)


 

 

자 저번시간에 연산프로퍼티는 값을 "저장"하기 보다는 그때그때 특정한 연산을 통해 값을 리턴해준다고 그랬죠?

그리고 클래스, 구조체에서 사용된다고 그랬어요.

 

클래스, 구조체는 저장 프로퍼티 이외에도 값을 저장하지 않는 연산 프로퍼티를 정의할 수 있는데, 바로 getter와 setter를 통해 다른 프로퍼티와 간접적으로 값을 검색하고 세팅합니다.

 

네!!!우리에게 익숙한 getter와 setter가 나왔어요. 바로 이 getter와 setter들이 "연산 프로퍼티"입니다.

Apple 예제를 볼까요?...라고 할라고 했는데, 예제가 상당히 기네요.

우리는 처음이니까 이 긴 예제는 나중에 보도록 하고, "연산프로퍼티"가 어떤것인지 먼저 짧게 볼게요.

 

 

class Point {

    var x: Int {

        get {

            return x

        }

        set(newValue) {

            x = newValue * 2

        }

    }

}

var p: Point = Point()

p.x = 12//error!

 

스택오버플로우에 있는 예제를 가져왔어요 :)

자. 일단 위 코드는 틀린코드에요! 

왜냐하면 "저장소"가 없거든요. 

위 x같은경우. 자기자신을 두배로 만들어주고, 자신을 리턴해주기때문에 이렇게 사용하면 안되고, 

값을 "저장"할 변수가 하나 있어야만해요. 

그래서, 제가 하고싶은 말은 getter와 setter를 사용하려면 그 연산된 값을 저장할 변수가 반드시 있어야만 해요!!

class Point {

 

    var tempX : Int = 1

 

    var x: Int {

        get {

            return tempX

        }

        set(newValue) {

            tempX = newValue * 2

        }

    }

}

 

var p: Point = Point()

p.x = 12

 

자. tempX라는 Point 클래스의 저장프로퍼티를 하나 만들어주었어요. (init만들어주기 싫어서 초기값을 줬습니다ㅎㅎ..)

tempX말고 x는, 이제 tempX에 대해 "연산"을 할거에요. 만약 값을 읽으려고 하면 tempX에 있는 값을 리턴하고, 값을 지정할 땐 2배로 해서 tempX에 지정하죠. 

 

봐봐요!!! 우리가 위에서 연산프로퍼티는 값을 "저장"하기 보다는 연산을 한다고 그랬죠? 바로 이뜻이에요!!

x라는 프로퍼티는 값을 저장하나요? 

아뇨. 값을 "연산"해서 tempX에 할당하거나 리턴하는 역할만 하는거에요.

그리고, 연산프로퍼티는(위 코드에서는 x) 반드시 var로 선언되어야 합니다. 값이 고정되어 있지 않기때문이에요.

엥..근데 궁금한점이 있습니다. 

set(newValue) {

     tempX = newValue * 2

}

 

이 set옆에 있는 newValue는 뭐죠? 우리는 newValue라는 것은 선언해 준적도 없는데 말이에요..

이해를 돕기 위해 

set(zedd) {

    tempX = zedd * 2

}

 

이렇게 바꿔볼게요. 이렇게 해도 전혀!! 문제가 없어요.

 

우리..? 흠흠 음..저는 java나 C++에서 getter와 setter를 만들 때 어떻게 했냐면, setter는 파라미터를 하나 받아서 그 파라미터를 해당 클래스 변수에 넣어주고!

getter는 파라미터를 아무것도 안받고 그냥 클래스변수를 리턴했었어요.

이것도 똑같아요!

 

var p: Point = Point()

p.x = 12

 

우리가 막 p.x = 12,23,30...이런식으로 여러 값을 넣을 수는 없죠? 반드시 한번에 한 데이터?만 들어가게 됩니다.

그것을 우리는 저 set옆에 있는 괄호에 넣은거에요. newValue와 zedd가 저 12라는 값을 넣어줄 파라미터 인것이죠.

하지만, set(zedd)대신 그냥 set 이라고도 할 수 있어요. 

이것을 Shorthand Setter Declaration라고 하나봐요. 

대신 조건이 있습니다. 

 

set {

     tempX = newValue * 2

}

 

괄호 없이 그냥 set만 쓴다면!!!!!!!!!!반드시!!!!!!!!!저 newValue라는 키워드를 사용해야합니다. 

zedd뭐 이런거 안되고, 반드시 "newValue"여야 하며, 이것만 인식합니다. 

 

class Point {

    var tempX : Int = 1

    var x: Int {

        get {

            return tempX

        }

        set {

            tempX = newValue * 2

        }

    }

}

var p: Point = Point()

p.x = 12

 

Shorthand Setter Declaration을 적용하면 위 코드처럼 되겠네요.

p.x = 12를 하면 !!!!!!!!!!!!!!!!!x에 값이 저장되는 것이 아니라!!!!!!!!!!!!!!

tempX에 12를 두배한 24가 저장이 되는 것@!!!!!!잊지마세요.

 

 

이제 조금 "연산 프로퍼티"에 대해서 감이 오시나요?! 그럼 우리 이제 Apple 예제를 보자구요 :)

길지만, 차근차근 보면 하나도 어렵지 않답니다. 

 

struct Point {

    var x = 0.0, y = 0.0 //이렇게 줄에 "저장 프로퍼티" 선언했네요 :)

}

 

struct Size {

    var width = 0.0, height = 0.0//역시나 입니다.

}

 

struct Rect {

 

    //저번에 배운 CGRect 비슷하다고 생각하시면 됩니다!!

    var origin = Point()//origin x,y좌표니 Point()타입으로 만들어주고

 

    var size = Size()//size 너비와 높이를 가지니 Size()타입으로 만들어줍니다

 

    var center: Point {

 

        //center 함은 어떤 사각형의 가운데인 "좌표"겠죠? 그러니 Point타입으로 선언해주고!! get set 나오는 것을 보니 center "연산 프로퍼티"임을 있네요.

 

        get {

            let centerX = origin.x + (size.width / 2)

            let centerY = origin.y + (size.height / 2)

            //get에도 위처럼 새로 변수를 선언하고 값을 할당 있어요. 리턴만 제대로 해주면 된답니다.

            //리턴하는 타입은 center 타입과 반드시 같아야해요. Point 타입.

 

            return Point(x: centerX, y: centerY)

 

        }

        set(newCenter) {

            origin.x = newCenter.x - (size.width / 2)

            origin.y = newCenter.y - (size.height / 2)

        }

    }

}

 

var square = Rect(origin: Point(x: 0.0, y: 0.0), size: Size(width: 10.0, height: 10.0))

 

let initialSquareCenter = square.center

 

print(initialSquareCenter)//(x: 5.0,y: 5.0)

 

square.center = Point(x: 15.0, y: 15.0)

 

print("square.origin is now at (\(square.origin.x), \(square.origin.y))")

 

// Prints "square.origin is now at (10.0, 10.0)"

 

자. 천천히 한번 읽어보세요 :)
square라는 Rect형 인스턴스를 하나 만들었어요. 
그리고 origin이 (0,0)이고 너비가 10. 높이가 10인 사각형을 하나 만들었습니다. 

자 아직 center의 get과 set은 한번도 안불렸어요!!!

그리고 다음으로 비로소

 

initialSquareCenter square.center 넣어줍니다. 

 

, 지금 보면 우리가 square.center 값을 넣어줬나요

그냥 지금 center 어떤값인지만 보려는거죠

그러니까 center라는 연산프로퍼티의 get 호출?한거에요.

 

origin (0,0)이고 너비와 높이가 10이었으니 center (5,5) 되겠네요.

 

 

 

!!!!다시한번 말씀드리지만, center라는 프로퍼티가 (5,5)라는 값을 "가지고"있는게 아니라!!!!!!!!!!!

 

Point 구조체의 x y 5라는 값을 가지고 있는거에요@!!@@

 

, 그럼 get 호출해보았으니 center set 호출해봅시다. 

 

그럼 center 어떤 "" 넣어주면 되겠네요? 

 

square.center = Point(x: 15.0, y: 15.0)

center는 Point타입이었으므로, Point타입을 넣어줘야겠죠? 

자. 이 코드가 실행되는 순간 center의 set이 불리게 됩니다. 

자. center의 set은 x에 15-5, y에 15-5를 하므로

origin좌표는 (10,10)이 됩니다.

왜냐면 우리는 지금 center에 값을 넣어줬거든요!!!

center가 (15,15)이고 너비가 10, 높이가 10이려면!

새로운 center인 15에서 너비와 높이를 반으로 한 값을 빼준것이 origin이 되니까요!

 

이렇게요 :)

위 코드에 

Shorthand Setter Declaration를 적용시켜볼까요? 

 

struct Point {

 

    var x = 0.0, y = 0.0 //이렇게 줄에 "저장 프로퍼티" 선언했네요 :)

 

}

 

struct Size {

 

    var width = 0.0, height = 0.0//역시나 입니다.

 

}

 

struct Rect {

 

    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)

 

        }

 

    }

 

}

위 코드가 되겠네요 :) newCenter대신에 newValue가 들어간 것. 보이시죠?

 

 

자!!! 이정도로 연산프로퍼티의 기본적인 개념설명은 마치도록 할게요 :)

이제 연산프로퍼티를 조금 더 깊게 알아보겠습니다 

연산 프로퍼티를 정의할 때, 꼭 저렇게 get, set둘다 만들어줘야 하느냐...

는 아닙니다!

 

연산 프로퍼티는 위 코드처럼 get, set둘다 가질 수 있지만, get만을 가질 수 있습니다. 

(set만 가지는 것은 안됩니다.)

 

get만 있는 연산 프로퍼티를 

Read-Only Computed Properties라고 해요 :)

말그대로 "읽기 전용"이죠.

get만 있을 때는, get을 "생략"해도 됩니다. 

 

  1. struct Cuboid {
  2. var width = 0.0, height = 0.0, depth = 0.0
  3. var volume: Double {
  4. return width * height * depth
  5. }
  6. }

이렇게요!

위 예제에서 volume에 특정한 값을 주는 set연산은 못하겠죠?

 

 

 

자! 어떠신가요 ㅎㅎ  Computed Property(연산 프로퍼티)에 대해서 조금 아시겠나요? 

간단하게 연산프로퍼티에 대해 정리해보면,

 

1. 클래스, 구조체, 열거형에 사용된다.

2. var로 선언해야한다.

3. 클래스, 구조체, 열거형에 값을 저장할 저장프로퍼티가 하나 있어야한다.==> 연산프로퍼티 자기 자신을 리턴하거나 값을 지정할 수 없다.

4. get, set을 동시에 구현 가능하며, get만 구현하는 것도 가능. 하지만 set만 구현하는 것은 안된다!

5. set의 파라미터를 생략할 수 있으며 생략했을 시, newValue라는 키워드를 사용한다. 

 

 

ㅎㅎㅎ흐아 연산프로퍼티가 끝났지만, 우리는 아직 프로퍼티에 대해 배울게 많아요 :) 

이 글이 저번 저장프로퍼티에 이어서, 연산프로퍼티를 이해하는데 도움이 되었으면 좋겠어요 XD 

: 저장프로퍼티 보러가기

 

그럼 안녕!

 

반응형

'Swift' 카테고리의 다른 글

Swift ) Properties - Type Properties  (4) 2017.10.13
Swift ) Properties - Property Observers(프로퍼티 옵저버)  (1) 2017.10.09
Swift ) Properties - Stored Property(저장 프로퍼티)  (5) 2017.10.06
Swift ) tuple  (3) 2017.10.02
Swift ) Types  (0) 2017.10.01