다음 코드는 구체적인 초기화 방법을 명시하지 않고 접근전에 초기화가 필요하게 만드는 코드이다.notNull함수를 이용해 값이 설정되지 않았다면 예외를 던지는 대리자를 제공한다
var shouldNotBeNull: String by Delegates.notNull<String>()
위에 선언된 shouldNotBeNull은 속성에 값이 제공되기 전에 접근을 시도하면 코틀린이 IllegalStateException을 던지게 된다. Delegates
는 object를 통한 싱글톤 클래스로 구현이되어있으며, ReadWriteProperty
인터페이스를 구현하는 NotNullVar
클래스 인스턴스를 리턴한다. NotNullVar
의 getValue에서 값이 null일경우, 예외를 던지도록 구현되어있다.문제 : 속셩의 변경을 가로채서, 필요에 따라 변경을 거부하고 싶다.
- 해답
변경감지에는
observable
함수를 사용하고, 변경의 적용 여부를 결정할 때는vetoable
함수와 람다를 사용한다.
다음은 observable과 vetoable함수의 시그니쳐이다.
public final inline fun <T> observable(initialValue: T, crossinline onChange: (kotlin.reflect.KProperty<*>, T, T) -> kotlin.Unit): kotlin.properties.ReadWriteProperty<kotlin.Any?, T>
public final inline fun <T> vetoable(initialValue: T, crossinline onChange: (kotlin.reflect.KProperty<*>, T, T) -> kotlin.Boolean): kotlin.properties.ReadWriteProperty<kotlin.Any?, T>
두 팩토리 함수 모두 T타입의 초기값과 람다를 인자로 받고, ReadWriteProperty 인터페이스를 구현한 클래스의 인스턴스를 리턴한다.
다음 코드는 observable과 vetoable을 사용한 예제이다.
var wathced: Int by Delegates.observable(1) {
property, oldValue, newValue ->
println("newValue is $newValue")
}
var checked: Int by Delegates.vetoable(0) {
property, oldValue, newValue ->
newValue >= 0 // 조건식 즉 BOOL이 리턴되어야 함.
}