Property [옵저버] - ehrldyd15/Swift_Skills GitHub Wiki
Property [옵저버]
프로퍼티옵저버
프로퍼티 값의 변화를 관찰하는 것으로, 저장프로퍼티에 추가할 수 있다.
새 값의 속성이 현재 값과 동일하더라도 속성 값이 설정되면 호출된다.
값이 저장되기 직전에 호출되는 willSet, 새 값이 저장된 직후에 호출되는 didSet이 있다.
1. willSet
willSet 옵저버를 구현하면 값이 저장되기 직전에 새로 저장될 값이 파라메터로 전달된다.
이때 파라메터 이름은 지정할 수 있지만, 파라메터 이름과 괄호를 따로 지정하지 않을 경우 newValue로 사용한다.
var name: String = "Unknown" {
willSet(newName) {
print("현재 이름 = \(name), 바뀔 이름 = \(newName)")
}
}
willSet 옵저버는 위와같이 구현을 하고 newName이라는 파라메터 이름을 내가 지정 가능하다.
var name: String = "Unknown" {
willSet { ✅
print("현재 이름 = \(name), 바뀔 이름 = \(newValue)") ✅
}
}
파라메터를 생략하게되면 newValue로 접근이 가능하다.
var name: String = "Unknown" {
willSet(newName) {
print("현재 이름 = \(name), 바뀔 이름 = \(newName)")
}
}
print(name) ✅ // Unknown
값을 변경하지 않고 호출을 하면 디폴드 값이 출력된다.
var name: String = "Unknown" {
willSet(newName) {
print("현재 이름 = \(name), 바뀔 이름 = \(newName)")
}
}
name = "ABC" ✅ // 현재 이름 = Unknown, 바뀔 이름 = ABC
2. didSet
didSet 옵저버를 구현하면 값이 저장된 직후에 이전 프로퍼티의 값이 파라메터로 전달된다.
이때 파라메터 이름은 지정할 수 있지만, 파라메터 이름과 괄호를 따로 지정하지 않을 경우 oldValue로 사용한다.
var name: String = "Unknown" {
didSet(oldName) {
print("현재 이름 = \(name), 바뀌기 전 이름 = \(oldName)")
}
}
didSet 옵저버는 위와같이 구현을 하고 oldName이라는 파라메터 이름을 내가 지정 가능하다.
var name: String = "Unknown" {
didSet { ✅
print("현재 이름 = \(name), 바뀌기 전 이름 = \(oldValue)") ✅
}
}
willSet과 마찬가지로 파라메터 부분을 지우면 oldValue로 접근할 수 있다.
var name: String = "Unknown" {
didSet(oldName) {
print("현재 이름 = \(name), 바뀌기 전 이름 = \(oldName)")
}
}
print(name) ✅ // Unknown
값을 변경하지 않고 출력하면 디폴트 값이 출력된다.
var name: String = "Unknown" {
didSet(oldName) {
print("현재 이름 = \(name), 바뀌기 전 이름 = \(oldName)")
}
}
name = "ABC"
print(name) ✅ // 현재 이름 = ABC, 바뀌기 전 이름 = Unknown
3. willSet과 didSet 동시구현
var name: String = "Unknown" {
willSet {
print("현재 이름 = \(name), 바뀔 이름 = \(newValue)")
}
didSet {
print("현재 이름 = \(name), 바뀌기 전 이름 = \(oldValue)")
}
}
name = "ABC"
✅ // 현재 이름 = Unknown, 바뀔 이름 = ABC
✅ // 현재 이름 = ABC, 바뀌기 전 이름 = Unknown
출력의 순서는 아래와 같다.
-
willSet이 먼저 실행
-
저장프로퍼티의 name의 값이 변경
-
didSet이 실행
연산프로퍼티도 프로퍼티옵저버 추가할 수 있다.
위에서 언급했듯이 프로퍼티옵저버는 저장프로퍼티에 한해서 추가할 수 있는데
연산프로퍼티도 프로퍼티옵저버를 추가할 수 있다.
(부모 클래스의 연산프로퍼티를 오버라이딩 할 경우 프로퍼티옵저버를 추가할 수 있다.)
class Human {
var name = "Unknown"
var alias: String {
get {
return name
}
set {
name = newValue
}
willSet { } ❌ // error! 'willSet' cannot be provided together with a getter
didSet { } ❌ // error! 'didSet' cannot be provided together with a getter
}
}
위 처럼 입력하면 에러가 발생한다.
왜냐하면 setter를 통해 값 변경을 할 수 있는데 굳이 프로퍼티 옵저버를 만들 이유가 없기 때문이다.
class Human {
var name = "Unknown"
var alias: String {
get {
return name
}
set {
name = newValue
}
}
}
class ABC: Human {
override var alias: String {
willSet {
print("현재 alias = \(alias), 바뀔 alias = \(newValue)")
}
didSet {
print("현재 alias = \(alias), 바뀌기 전 alias = \(oldValue)")
}
}
}
let abc: ABC = .init()
abc.alias = "ABC"
✅ // 현재 alias = Unknown, 바뀔 alias = ABC
✅ // 현재 alias = ABC, 바뀌기 전 alias = Unknown