새소식

인기 검색어

iOS/Swift

[Swift] Key Value Coding(KVC), Key Value Observing(KVO)

  • -

Key의 개념

  • Swift의 KeyPath, KVC, KVO 자꾸나오는 Key의 개념은?
    • 문자열(Key)를 의미
    • 이 key값을 통해 instance의 property value에 간접적으로 접근하게 해주는 Objective-C에서 나온 개념

KVC, KVO가 생기게 된 이유

Objective - C로 개발하던 시절에는 MVC 패턴이 정답이라고 생각하던 시기

MVC에서 가장 중요한것은 Model과 View의 Sync를 맞추는 일

여기서 Controller는 2가지 역할을 수행하여야 함

  1. Model의 변화를 View에 반영
  2. View의 Interaction을 Model에 반영

View나 Model에서 Action이 일어날 때마다 이 2가지 과정을 거쳐

일일이 상태값을 업데이트 해주고 View와 Model을 동기화 해줘야하는 문제에 직면

이를 나누지 말고 묶어서 서로 업데이트 해주면 되지 편리하지 않을까 ? 라는 관점에서 나온 것

Key Value Coding

  • 객체의 값을 직접 가져오지 않고 Key 또는 KeyPath를 이용해서 간접적으로 데이터를 가져오거나 수정하는 방법
  • Objective-C의 것이기 때문에 NSObject가 지고 있으므로 NSObject의 서브클래스여야 가능
  • KVC는 Objective-C Dynamic Dispatch 특성에 의존하므로 프로퍼티 앞에 @objc 어노테이션을 붙여서 사용
  • key는 String
  • key는 일반적으로 객체에 정의된 accessor method 또는 인스턴스 변수의 "이름"
  • key는 특정 규칙을 따름
    • ASCII로 인코딩 되어야 함
    • 소문자로 시작해야함
    • 공백이 없어야함

KVC는 NSKeyValueCoding 을 준수

NSKeyValueCoding | Apple Developer Documentation

 

NSKeyValueCoding | Apple Developer Documentation

A mechanism by which you can access the properties of an object indirectly by name or key.

developer.apple.com

 

NSKeyValueCoding에는 다양한 getter와 setter가 있는데 가장 많이 사용하는 4가지의 사용법을 알아보자

get method

set method

KVC 예제

  • objctive-C 에서 생긴 개념이기에 NSObject를 상속하고 프로퍼티에 @objc 어노테이션을 사용

ForKey

class Point: NSObject {
    @objc var x: Double
    @objc var y: Double
}

let point = Point(x: 0, y: 0)
point.value(forKey: "x") // 0
point.setValue(5, forKey: "x")
point.value(forKey: "x") // 5

key값을 이용해 value에 접근할 수 있다. 그렇다면 keypath는 언제 쓸까 ?

ForKeyPath

객체안에 객체가 들어가 있을 때 사용한다. Key로는 객체 내부의 프로퍼티만 접근가능하기 때문

class Point: NSObject {
    @objc let x: Double
    @objc let y: Double
}

class Size: NSObject {
    @objc var width: Double
    @objc var height: Double
}

class Rect: NSObject {
    @objc var point: Point
    @objc var size: Size
    @objc var min: Double
    @objc var max: Double
}

let rect = Rect(
    point: .init(x: 1, y: 2),
    size: .init(width: 3, height: 4),
    min: 5,
    max: 6
)

rect.value(forKey: "point") // <Key.Point: 0x60000183b060>

위와 같이 선언되어 있을 때 Rect객체의 Point의 x값을 확인하려면 KeyPath를 이용할 수 밖에 없다.

rect.value(forKeyPath: "point.x") // 1
rect.value(forKeyPath: "point.y") // 2
rect.value(forKeyPath: "size.width") // 3
rect.value(forKeyPath: "size.height") // 4
rect.value(forKeyPath: "min") // 5
rect.value(forKeyPath: "max") // 6

rect.setValue(100, forKeyPath: "point.x") // rect.point.x = 100
rect.setValue(15, forKeyPath: "min") // rect.min = 15

rect.setValue(Point(x: 10, y: 20), forKey: "point") // rect.point = Point(10, 20)

KVO - Key Value Observing

  • NSObject를 상속하고 프로퍼티에 @objc dynamic 을 붙혀 사용
class MyPoint: NSObject {
    @objc dynamic var x: Double
    @objc dynamic var y: Double
}

let myPoint = MyPoint(x: 0, y: 0)

myPoint의 x,y의 값이 변경될 때마다 특정 작업을 하기위해 observing 하려면 observe 함수를 정의한다.

var observer: NSKeyValueObservation? = myPoint.observe(\\.x, options: [.old, .new]) { myPoint, change in
	print("myPoint.x의 현재 값 \\(change.oldValue!)가 \\(change.newValue!)로 변경")
}
myPoint.x = 2 // 위 코드로 인해 "myPoint.x의 현재 값 0.0가 2.0로 변경" 출력
observer = nil
  1. myPoint의 프로퍼티 x에 observer 추가
  2. 프로퍼티가 변경됨
  3. observer의 changeHandler 호출
  4. handler 내의 클로저 실행

KeyPath

  • 어떤 값을 observe할 것인지를 정함
  • 위 예시에선 x를 observe 하기 때문에 x 이외의 값은 아무리 바꾸어도 observer가 실행되지 않는다.
let myPoint = MyPoint(x: 0, y: 0)

var observer: NSKeyValueObservation? = myPoint.observe(\\.x, options: [.old, .new]) { myPoint, change in
    print("myPoint.x의 현재 값 \\(change.oldValue!)가 \\(change.newValue!)로 변경")
}

myPoint.x = 2 // myPoint.x의 현재 값 0.0가 2.0로 변경

myPoint.y = 1 // 아무일 없음
myPoint.y = 2 // 아무일 없음
myPoint.y = 3 // 아무일 없음

observer = nil

options

old, new

new와 old는 willSet, didSet의 oldValue, newValue를 생각하면 됨

old, new만 주었을 때는 초기화 후 x의 값에 새로운 값을 주었을 때만 handler 호출

var myPoint = MyPoint(x: 0, y: 0)
var observer: NSKeyValueObservation? = myPoint.observe(\\.x, options: [.old, .new]) { myPoint, change in
    print(change.oldValue, change.newValue)
		// Optional(0.0) Optional(1.0)
}

myPoint.x = 1

observer = nil

initial

초기화 시에도 호출 할것인지를 묻는 것

initial을 주면 초기화 시에도 handler 호출

var myPoint = MyPoint(x: 0, y: 0)
var observer: NSKeyValueObservation? = myPoint.observe(\\.x, options: [.initial, .old, .new]) { myPoint, change in
    print(change.oldValue, change.newValue)
		// nil Optional(0.0)
		// Optional(0.0) Optional(1.0)
}

myPoint.x = 1

observer = nil

prior

이전 상태의 값과 현재 상태의 값을 둘 다 주는 것

var myPoint = MyPoint(x: 0, y: 0)
var observer: NSKeyValueObservation? = myPoint.observe(\\.x, options: [.prior, .old, .new]) { myPoint, change in
    print(change.oldValue, change.newValue)
	  // Optional(0.0) nil <- myPoint.x = 1 이 실행되기 전의 상태 값 newValue가 없기에 nil
		// Optional(0.0) Optional(1.0)
}

myPoint.x = 1

observer = nil

initial을 안주어서 초기화 상태 말고 x가 1로 변경될 때 변경되기 전의 상태 값과 변경되고 난 후의 상태값 을 호출

initial을 주게되면 ?

var myPoint = MyPoint(x: 0, y: 0)
var observer: NSKeyValueObservation? = myPoint.observe(\\.x, options: [.initial, .prior, .old, .new]) { myPoint, change in
    print(change.oldValue, change.newValue)
		// nil Optional(0.0)
		// Optional(0.0) nil 
		// Optional(0.0) Optional(1.0) 
}

myPoint.x = 1

observer = nil

initial은 prior을 벗어난것을 확인 할 수 있다.

KVO의 장단점

장점

  • Model, View 두 객체간의 동기화 가능
  • 외부 라이브러리나 다른 사람이 작성한 객체의 경우 코드 변경 없이 내부의 값 관찰 가능
    • 단 해당 객체가 NSObject를 무조건 상속받고 있어야 하며 @objc dynamic도 붙어 있어야 함 …
    • 장점맞나 ?
  • KeyPath를 사용하여 프로퍼티를 관찰하므로 중첩된 프로퍼티도 관찰 가능
    • ex) rect.point.x

단점

  • NSObject를 상속받아야 함
    • object-c 런타임에 의존하게 됨
    • static dispatch가 dynamic dispatch가 된다는 단점

번외

setValue시 this class is not key value coding-compliant for the key 에러가 뜨는 경우가 있는데

이 경우는 말 그대로 key값으로 value를 변경할 수 없을 때 뜨는 에러인데

object.setValue(value, key)일 때 보통 아래 경우라 볼 수 있다.

  • object가 nil
  • class Point: NSObject { @objc var x: Double @objc var y: Double } let point: Point? point.setValue(1, "x")
  • key값이 잘못 됨
  • class Point: NSObject { @objc var x: Double @objc var y: Double } let point = Point(x: 0, y: 0) point.setValue(1, "XX")
  • value 타입이 맞지 않음
  • class Point: NSObject { @objc var x: Int @objc var y: Int } let point = Point(x: 0, y: 0) point.setValue(1.4, "x")
  • let 으로 선언되어 있음
  • class Point: NSObject { @objc let x: Double @objc let y: Double } let point = Point(x: 0, y: 0) point.setValue(1, "x")

참고

Using Key-Value Observing in Swift | Apple Developer Documentation

 

Using Key-Value Observing in Swift | Apple Developer Documentation

Notify objects about changes to the properties of other objects.

developer.apple.com

NSKeyValueObserving | Apple Developer Documentation

 

NSKeyValueObserving | Apple Developer Documentation

An informal protocol that objects adopt to be notified of changes to the specified properties of other objects.

developer.apple.com

Key-Value Coding Programming Guide: About Key-Value Coding

 

Key-Value Coding Programming Guide: About Key-Value Coding

Key-Value Coding Programming Guide

developer.apple.com

NSKeyValueObservingOptions | Apple Developer Documentation

 

NSKeyValueObservingOptions | Apple Developer Documentation

The values that can be returned in a change dictionary.

developer.apple.com

[iOS] KVO(Key-Value Observing)

 

[iOS] KVO(Key-Value Observing)

KVO(Key-Value-Observiing)란? KVO는 A객체에서 A의 변경사항을 B객체에게 알리기 위해 사용하는 코코아 프로그래밍 패턴이다. KVO를 사용하면 다른 개체의 특정 속성이 변경될 때 알림을 받도록 객체를

clamp-coding.tistory.com

[iOS - swift] KVC (Key Value Coding), KVO (Key Value Observing), value(forKey:), setValue(_:forKey:) 개념

 

[iOS - swift] KVC (Key Value Coding), KVO (Key Value Observing), value(forKey:), setValue(_:forKey:) 개념

Key의 개념 스위프트의 KeyPath, KVC, KVO 자꾸나오는 Key의 개념은? 문자열(Key)를 의미하고 이 key값을 통해 인스턴스의 프로퍼티 값(Value)에 간접적으로 접근하게 해주는 Objective-C에서 나온 개념 KVC (Key

ios-development.tistory.com

Key-Value Coding(KVC) / KeyPath in Swift

 

Key-Value Coding(KVC) / KeyPath in Swift

안녕하세요 :) Zedd입니다. 오늘은 KVC에 대해서 공부해보겠습니다. # KVC - Key-Value Coding 의 약자 - 객체의 값을 직접 가져오지않고, Key 또는 KeyPath 를 이용해서 간접적으로 데이터를 가져오거나 수정

zeddios.tistory.com

Key-Value Observing(KVO) in Swift

 

Key-Value Observing(KVO) in Swift

안녕하세요 :) Zedd입니다. 오늘은 KVO에 대해서 공부! # KVO - Key-Value Observing의 약자 - 객체의 프로퍼티의 변경사항을 다른 객체에 알리기 위해 사용하는 코코아 프로그래밍 패턴 - Model과 View와 같이

zeddios.tistory.com

KVC/KVO in Objective-C

 

KVC/KVO in Objective-C

KVC/KVO 는 Apple Framework에서 중요한 부분을 담당한다. 한번 공부해보자.

velog.io

[iOS] KVC, KVO

 

[iOS] KVC, KVO

Key-Value Coding 객체의 값을 직접 가져오지 않고, Key 또는 KeyPath를 이용해서 간접적으로 데이터를 가져오거나 수정하는 방법\\BaseType.ProperyName으로 만들어준다.KeyPath : Read onlyWritableKeyPath : v

velog.io

KVC와 KVO의 활용 및 목적 - 야곰닷넷

 

KVC와 KVO의 활용 및 목적 - 야곰닷넷

최근에 KVC와 KVO에 대해서 검색을 했습니다. 각각에 대한 개념이나 예시 같은 것은 많이 나와있지만 왜 […]

yagom.net

 

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.