티스토리 뷰

반응형

안녕하세요 :) Zedd입니다. 오늘은 저번 글에 이어서 프로퍼티 옵저버라는 것을 볼거에요 :)

이 글을 보시기전에

: < Properties - Stored Property(저장 프로퍼티) 읽으러가기 > 

: < Properties - Computed Property(연산 프로퍼티) 읽으러가기 >


위 두 글을 꼭!! 읽고와주세요 :)

시작할게요!! 이 글 역시.."프로퍼티 옵저버"라고 언급할게요 :)




Property Observers(프로퍼티 옵저버)



자. "프로퍼티 옵저버"하면 어떤게 떠오르시나요?

프로퍼티 감시자? 뭐 이런 것 같죠?

프로퍼티를 왜 감시하지..?




우리 이때까지 저장프로퍼티와, 연산 프로퍼티를 배웠죠? 이 프로퍼티들을 "감시"할 수 있습니다.


Apple 왈 : Property Observers(프로퍼티 옵저버)를 정의해서 프로퍼티 값의 변경을 모니터링 할 수 있습니다. 프로퍼티 옵저버는 자신이 정의한 "저장 프로퍼티"에 추가 할 수 있으며, super class(부모클래스)를 상속한 프로퍼티에도 추가 할 수 있습니다. 



프로퍼티 옵저버에 대한 설명을 좀 더 볼까요?


프로퍼티 옵저버는 프로퍼티 값의 변화를 관찰하고, 이에 응답합니다.

프로퍼티 옵저버는 새로운 값이 프로퍼티의 현재값과 "동일하더라도" 속성의 값이 설정(set)될 때 마다 호출됩니다.


lazy 저장 프로퍼티를 제외하고, 정의된 저장 프로퍼티에 프로퍼티 옵저버를 추가할 수 있습니다. 

또한, 하위 클래스 내의 프로퍼티를 재정의하여, 상속된 프로퍼티(저장프로퍼티 or 연산프로퍼티 어느것이든)에도 프로퍼티 옵저버를 추가할 수 있습니다.

오버라이드(override)되지 않은 연산프로퍼티에 대한 프로퍼티 옵저버는 연산프로퍼티 setter에서 해당 값의 변경을 관찰하고 이에 응답할 수 있으므로 정의 할 필요 없습니다. 



정리하자면, 원래는 "저장 프로퍼티"에만 프로퍼티 옵저버를 추가할 수 있는데, 부모클래스를 상속하는 하위클래스 프로퍼티는 저장프로퍼티든, 연산프로퍼티든 프로퍼티 옵저버를 추가할 수 있나보네요.


프로퍼티 옵저버에 대한 개념 설명은 이까지 하도록 하고, 프로퍼티 옵저버에는 어떤게 있고 어떻게 사용하는지 봅시다 :)


우리는 하나의 프로퍼티에 대해 다음 옵저버 중 하나 또는 두가지 모두 정의 할 수 있어요.


willSet - 값이 저장되기 직전에 호출됩니다. 

didSet - 새로운 값이 저장된 직후에 호출됩니다. 


아하! 정말 직관적인 이름이네요 XD..

먼저, willSet을 더 살펴봅시다.


만약 willSet옵저버를 구현했다면, 새로운 프로퍼티의 "값"이 상수 매개변수(constant parameter)로 전달됩니다. 

willSet구현의 일부로, 이 매개변수(constant parameter)의 이름을 지정할 수 있습니다. 구현내의 매개변수 이름과 괄호를 쓰지 않으면 newValue라는 기본 매개변수 이름을 사용하여 이 매개변수를 사용할 수 있습니다. 


마찬가지로, didSet옵저버를 구현한다면 이전 프로퍼티 값을 포함하는 상수 매개변수(constant  parameter)가 전달됩니다. 

매개변수의 이름을 지정하거나, oldValue라는 기본 매개변수 이름을 사용할 수 있습니다. 

자체적으로 설정한 옵저버 내에서 프로퍼티에 값을 할당하면, 할당한 새 값이 방금 설정한 값으로 바뀝니다. 



그리고 프로퍼티 옵저버를 사용하실 때 주의할 점이 있습니다!


부모클래스 프로퍼티의 willSet, didSet 옵저버는 부모클래스 initializer가 호출된 후!!!! 자식클래스의 initializer에서 set될때 호출됩니다. 

부모클래스 initializer가 호출되기 전에, 클래스가 자체 프로퍼티들을 setting하는 동안은 옵저버들은 호출되지 않습니다. 


말로 해서는 잘 모르겠네요 :)

예제를 봅시다.


class StepCounter {

    var totalSteps: Int = 0 {

        willSet(newTotalSteps) {

            print("totalSteps \(newTotalSteps) 설정하려고 합니다")

        }

        didSet(oldTotalSteps) {

            if totalSteps > oldTotalSteps  {

                print("\(totalSteps - oldTotalSteps)걸음이 추가되었습니다.")

            }

        }

    }

}

let stepCounter = StepCounter()

stepCounter.totalSteps = 200

// About to set totalSteps to 200

// Added 200 steps

stepCounter.totalSteps = 360

// About to set totalSteps to 360

// Added 160 steps

stepCounter.totalSteps = 896

// About to set totalSteps to 896

// Added 536 steps


위 예제는, 간단하게 말해서 만보기 예제에요! 

willSet과 didSet이 쓰였네요. 자세히 볼까요? 



class StepCounter {


//totalSteps "저장 프로퍼티"입니다!!

    var totalSteps: Int = 0 {


       willSet(newTotalSteps) {


            print("totalSteps \(newTotalSteps) 설정하려고 합니다")

        }


        didSet(oldTotalSteps) {


            if totalSteps > oldTotalSteps  {


                print("\(totalSteps - oldTotalSteps)걸음이 추가되었습니다.")

            }

        }

    }

}

자. 우리 위에서 배웠죠? 프로퍼티 옵저버(willSet, didSet)은 "저장프로퍼티"에 추가될 수 있다구요.

그러니까 위에서 선언한 totalSteps는 "저장프로퍼티"겠네요 :)


자, totalSteps이라는 저장프로퍼티에 옵저버를 걸어준 것 같네요. willSet과 didSet이요!

willSet을 먼저 봅시다. willSet은 값이 저장되기 직전에 호출됩니다..라고 했죠? Set을 할 거라는 will이 들어갔으니까요 :)

그리고 파라미터로 newTotalSteps이라는 것을 받네요. 


didSet은 뭐라고 그랬죠? 새로운 값이 저장된 직후에 호출됩니다...라고 그랬죠? 

원래 예제에 didSet에는 파라미터가 없었는데, 제가 추가해줬어요 :)  

이제 StepCounter의 저장프로퍼티인 totalSteps에 값을 추가해줘봅시다. 

let stepCounter = StepCounter()

stepCounter.totalSteps = 200

자. 그럼 totalSteps을 어떤값으로 set해볼거에요. 200으로 set해주면 어떤일이 일어날까요?

먼저 값이 저장되기 "직전에" 호출되는 willSet이 불리겠네요. willSet의 파라미터인 newTotalSteps에는 200이 들어가게 될거에요. 그리고 "totalSteps 200 설정하려고 합니다"라고 콘솔창에 뜨게 되겠죠!


willSet이 불리고 난 뒤에, didSet이 불릴텐데요! 

자, didSet은 뭐였죠? 값이 설정된 "직후에" 불린다고 했으니, 이미 totalSteps에는!!! 200이라는 값이 설정된 후에요!!! 이 사실을 꼭 기억해주세요.


 didSet은 주의해서 한번 봅시다.  didSet뒤에 oldTotalSteps이라고 파라미터 이름이 있죠? 

이건 위에서 우리가 준 200이 아니라!!!!!!!!!!!!!!!!!!!(완전중요)

totalSteps이라는 저장프로퍼티의 "설정하기 전 값"이에요. 

위에서 totalSteps은 처음에 0으로 초기화해줬죠?

그러니까, oldTotalSteps은 200이 아니라 0이에요. willSet과 다르게 말이에요.

그럼 이제, didSet이 수행되었으니 totalSteps(=200)에서 oldTotalSteps(=0)을 뺀 

"200걸음이 추가되었습니다."가 콘솔에 출력될거에요.


음..조금 헷갈리시죠?

한번만 더 해봅시다 :)

stepCounter.totalSteps = 360

자! 이번엔 totalSteps을 360으로 줬어요!

그럼 어떠한 "값"을 줬으니 willSet이 불리겠죠?

"totalSteps 360 설정하려고 합니다"라고 콘솔에 출력되겠고,

didSet이 불리기 직전에 totalSteps은 360으로 바뀔거에요.


자. 이제 didSet이 불리겠죠? didSet의 파라미터인 oldTotalSteps은 뭐라고 그랬죠?!?!

네 360으로 설정하기 이전의 값이 저장되어있다고 그랬죠?

360으로 설정하기 전이 200이었으니..

현재 totalSteps(=360)에서 oldTotalSteps(=200)을 뺀

"160걸음이 추가되었습니다."가 출력되겠죠!?




willSet의 newTotalSteps. didSet의 oldTotalSteps을 생략 할 수도 있다고 그랬죠?

생략하면 Swift에서 지정한 키워드를 써야한다고 그랬습니다 :)

willSet의 경우에는 newValue였고, didSet의 경우에는 oldValue였어요!


class StepCounter {


    //totalSteps "저장 프로퍼티"입니다!!

    var totalSteps: Int = 0 {

        willSet {

            print("totalSteps \(newValue) 설정하려고 합니다")

        }

        didSet {

            if totalSteps > oldValue  {

                print("\(totalSteps - oldValue)걸음이 추가되었습니다.")

            }

        }

    }

}



자 어떠신가요. 프로퍼티 옵저버인 willSet과 didSet을 조금 아시겠나요?


다음으로 넘어갈게요 :)



전역변수와 지역변수



프로퍼티를 계산하고 관찰하기 위해서 위에서 설명한 프로퍼티 옵저버 기능은 전역변수와 지역변수에서도 사용할 수 있습니다.


자. 전역변수와 지역변수는 다들 아시죠?

전역변수는 함수, 메소드, 클로저 또는 type context외부에 정의되는 변수에요. 

지역변수는 함수, 메소드 또는 closure context에서 정의되는 변수에요. 


이전에 보던 전역변수와 지역변수는 모두 저장변수(stored variable)에요. 

저장프로퍼티같은 저장변수(stored variable)는 특정 타입의 값에 대한 저장소를 제공하고, 해당 값을 설정(set)및 검색할 수 있도록 합니다.

그러나 전역 또는 지역범위 안에서 연산변수(computed variable)를 정의할 수 있으며 저장변수(stored variable)를 위한 옵저버를 정의할 수도 있습니다. 연산변수(computed variable)은 값을 "저장"하는 대신 값을 연산하며. 연산프로퍼티와 동일한 방식으로 작성됩니다. 


전역 상수 및 변수는 게으른 저장 프로퍼티(lazy stored Property)와 비슷한 방식으로, 항상 게으르게 연산됩니다.


게으른 저장 프로퍼티(lazy stored Property)와 달리, 전역 상수와 변수는 "lazy"라는 키워드가 필요없습니다. 

지역 상수와 변수는 게으르게 연산되지 않습니다. 


그러니까!! 정리하면 


1. 전역상수(global constant)와 전역변수(global variable)은 항상 게으르게 연산된다. == 즉, 필요할 때 초기화.

2. 전역상수(global constant)와 전역변수(global variable)은 연산 프로퍼티와는 다르게 lazy키워드가 필요없다.

3. 지역상수(local constant)와 지역변수(local variable)은 게으르게 연산되지 않는다. 


입니다!




어떠신가요 :) 프로퍼티 옵저버에 대해서 조금 아시겠나요? 천천히 읽어보시면 잘 이해하실 수 있을거에요 XD....

이전 프로퍼티 시리즈를 다 읽고오셔야만 다 이해가 가니까 꼭!!!! 저장프로퍼티연산프로퍼티에 대해서 알고 이 글을 읽으셨으면 좋겠어요!

그럼 다음글은 프로퍼티의 마지막!!!!!!!타입 프로퍼티입니다.

안녕!!




반응형