[Swift] class와 struct에서 didSet의 차이
왜 이 글을 쓰게 되었는가
며칠전에 이런 코드를 봤따.
@IBOutlet weak var button: UIButton! {
didSet {
button.backgroundColor = .red
}
}
didSet
에 해당 Outlet
의 초기 설정을 몰아넣는 것!
“그러면 button
의 속성이 바뀔때 마다 didSet
이 불리는거 아녜요? ㅇㅂㅇ?” 라고 질문했더니
“프로퍼티라면 그렇게 동작하겠지만 IBOutlet
은 class
라 저 button
자체를 바꾸지 않는 이상 didSet
이 호출되지 않아요. ” 라고 답변해주셨ㄷㅏ.
ㅇㅖ? ㅠ… 방과 후 블로그 시작합니다..
깨달음의 여정…🚗
class Foo {
var bar = 1
}
var test: Foo = Foo() {
didSet {
print("변경사항 있다!")
}
}
test.bar = 1 // 아무일도 일어나지 않는다
아니 나는 이러면 당연히 “변경사항 있다”가 프린트 될줄 알았지 ㅇㅅㅇ 근데 아무일도 일어나지 않는다니..! 이게 어찌된 일이요 didSet
양반!
여윽시 구글에는 비슷한 질문이 나와있었다. 답변을 요약해보면 아래와 같다.
didSet
이 reference type (ex. class
)에 달려있을 때
didSet
observer가 달려있는 애(test
)는class
인스턴스로 reference type임.- reference type의 instance는 제자리에서 변할 수 있음 (in place)
- 즉,
test
자체를 바꾼게 아니라test.number
을 바꿨기 때문에 아무일도 일어나지 않음 test = Foo()
이렇게 하면didSet
동작
didSet
이 value type (ex. struct
)에 달려있을 때
- value type은 비록 그렇게 보일지라도 실제로는 제자리에서 변할 수 없음 (not mutable in place)
- value type의 instance를 변경했다고 하면, 다른 instance로 원래 instance를 변경하는 것임
test.bar = 1
이어도 인스턴스가 변경되는 것이기 때문에didSet
동작
오키오키 IBOutlet
은 class
라 reference type 이기 때문에 해당 인스턴스 자체를 갈아 끼우지 않는 이상 didSet
이 동작하지 않는거였군!
마무리
사실 class
와 struct
의 이해의 부족에서 나온 문제였나? 싶기도 하다 ㅋㅎ 지금이라도 좀 더 알았으면 됐지 모~
보너스 — Outlet의 didSet 은 언제 trigger 되는가
Outlet
프로퍼티는class
가 막 초기화 될 때는nil
상태nib
으로부터 object가 초기화 될 때에 값을 갖게 됨- 모든
Outlet
이 nil이 아님을 확신할 수 있을때는viewDidLoad
때 - 따라서
Outlet
에 있는didSet
옵저버는viewDidLoad
바로 전에 호출 - 따라서
Outlet
프로퍼티 다룰 때 조심해야 함. 예를들어prepareForeSegue
때 접근하려고 하면 nil 받게 될 것