Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KVO 동작 방식에 대해 설명하시오. #13

Open
Do-hyun-Kim opened this issue Sep 2, 2023 · 4 comments
Open

KVO 동작 방식에 대해 설명하시오. #13

Do-hyun-Kim opened this issue Sep 2, 2023 · 4 comments
Labels
Swift Swift CS 개념 공부

Comments

@Do-hyun-Kim
Copy link
Contributor

No description provided.

@Do-hyun-Kim Do-hyun-Kim added the Swift Swift CS 개념 공부 label Sep 2, 2023
@Do-hyun-Kim
Copy link
Contributor Author

KVO 동작 방식에 대해 설명하시오.

KVO 이란?

  • 객체의 프로퍼티의 변경사항을 다른 객체에 알리기 위해 사용하는 코코아 터치 프로그래밍 패턴
  • Model과 View와 같이 논리적으로 분리된 파트간의 변경사항을 전달하는데 유용하다.
  • NSObject를 상속한 클래스에서만 KVO 를 사용 할 수 있다.

KVO 사용 방법

  • Observing이 필요한 객체에게 NSObject를 상속 받도록 한다.
  • Observing 하려는 Property@objc 속성과, dynamic 키워드를 부여한다.
  • key Path를 사용하여 observe(_:options:changeHandler:)를 호출하여 Observing을 수행한다.
class Person: NSObject {
    
    let name: String
    @objc dynamic var age: Int
    @objc dynamic var car: String = "BMW"
    
    init(name: String, age: Int, car: String) {
        self.name = name
        self.age = age
        self.car = car
    }
    
}

var jenny: Person = Person(name: "jenny", age: 20, car: "아반떼")

jenny.observe(\.car, options: [.old, .new, .initial, .prior]) { (object, change) in
    print("\(object.name)의 차가 \(change.oldValue) 에서 \(change.newValue)로 바꿨다. ")
}

jenny.observe(\.age, options: [.old, .new]) { (object, change) in
    print("\(object.name) 나이가 \(change.oldValue) 에서 \(change.newValue) 로 변경 되었다. ")
}



jenny.age = 24
jenny.age = 30

jenny.car = "K3"

KVO Options

  • old : 변경 전 값이 반환된다.
  • new : 변경 후 값이 반환된다.
  • initial : 초기화값에 대한 값을 반환된다.
  • prior : 변경 전,후 상태 모두 파악하여 반환된다.

KVO 장점

  • 두 객체간의 동기화, Model과 View 같이 분리된 파트간의 변경사항을 전달 가능하게 한다.
  • 프로퍼티의 값 번경 전(old Value), 변경 후(new Value) 를 관찰 할 수 있다.

KVO 단점

  • Objective-C 런타임에 의존적이며 dynamic 키워드로 인해 dynamic Dispatch로 활성화 하게 된다.
  • NSObject를 상속한 class 에서만 사용이 가능하다.

📝 참고 사이트

@ronick-grammer
Copy link
Contributor

KVO(Key-Value Observing) 란

클래스 오브젝트의 프로퍼티(Key)에 대한 값(Value)의 변화를 감지(Observing)할 수 있는 Cocoa 프로그래밍 패턴이다.

NSObject를 상속해야 한다.

KVO 를 구현 하기 위해서는 NSObject 클래스를 상속받아야 한다. '상속'받아야 하기 때문에 class에서만 구현할 수 있다.

class Observed: NSObject {
   ...
}
  • KVO 는 NSKeyValueObserving 프로토콜을 기반으로 동작한다.
  • NSObject클래스는 NSKeyValyeObserving 프로토콜을 채택/준수(구현)하고 있다.

*NSKeyValueObserving: KVO 구현을 위한 프로토콜이다. Swift에서는 공식적으로 지원하지 않는 프로토콜이다.

dynamic 키워드를 사용해야 한다.

  • dynamic 키워드는 Objective-C 런타임에서 dynamic dispatch 를 동작시켜주는 Objective-C 의 키워드이다.
  • Objective-C와 Swift와 상호연동되어야 하므로 @objc 키워드 역시 붙여 주어야 한다.
  • class의 프로퍼티를 dynamic 으로 선언하면 해당 프로퍼티를 키패스(KeyPath = /.)로 사용하여 프로퍼티의 메모리상 주소를 찾을 수 있게 된다.
class Observed: NSObject {
    @objc dynamic var value: String = ""
}

observe(_ keyPath:options:changeHandler:) 를 사용하여 관찰한다.

class가 NSObject를 상속하였고, dynamic 키워드로 관찰할 수 있는 프로퍼티 역시 설정하였다면 observe(_keyPath:options:changeHandler:) 메서드를 호출하여 프로퍼티를 관찰할 수 있다.

class Observed: NSObject {
    @objc dynamic var observedProperty: String = ""
}

var observedObj = Observed()

observedObj.observe(\.observedProperty, options: [.initial, .new, .old, .prior]) { obj, observedProperty in
    print("newValue: ", observedProperty.newValue)
    print("oldValue: ", observedProperty.oldValue)
    print("isPrior: ", observedProperty.isPrior)
}

observe(_ keyPath:options:changeHandler:)

  • keyPath: KeyPath<Observed, Value>: dynamic 키워드로 선언된 관찰할 프로퍼티
  • options: NSKeyValueObservingOptions: 관찰할 프로퍼티에 대한 옵션 값.
    • .initial: 초기값 관찰
    • .new: 값 수정시, 새로운 값 관찰, 생략시
    • .old: 값 수정시, 이전 값 관찰
    • .prior: 값 수정시, 값의 변화에 대한 상태(willChange)를 관찰
  • changeHandler: (Oberved, NSKeyValueObservedChange<Value>) -> Void : 값 수정시 관찰할 수 있는 클로저
    • Oberved: 관찰할 객체
    • NSKeyValueObservingOptions.new 생략시 NSKeyValueObservedChange<Value>.newValuenil
    • NSKeyValueObservingOptions.old 생략시 NSKeyValueObservedChange<Value>.oldValuenil
    • NSKeyValueObservingOptions.initial 생략시 초기값 관찰하지 않음
    • NSKeyValueObservingOptions.prior 생략시 NSKeyValueObservedChange<Value>.isPrior 값은 항상 false

📝 참고 사이트

@vichye-1
Copy link

vichye-1 commented Sep 7, 2023

KVO 란?

  • Key-Value Observing 의 약자
  • 특정한 객체가 변경될 때마다 알림을 받을 수 있도록 해주는 코코아 프로그래밍 패턴
  • 모델과 뷰 등 논리적으로 분리된 파트 간에 변경사항을 전달하는 데 유용하다
  • NSObject를 상속한 클래스에서만 KVO를 사용할 수 있다.

사용 방법

  • @objc dynamic 을 붙여서 사용한다
  • observe 함수를 호출한다
  • keyPath는 관찰할 변수를 설정해 준다. → \.변수명 과 같은 형식으로 넣어준다
  • option에는 NSKeyValueObservingOptions 타입을 넣어주는데, .new, .old, .initial, .prior 를 넣을 수 있다.
    • .old : 변경 전 값 반환
    • .new : 변경 후 값 반환
    • .initial : observer 등록 완료 전 observer에게 알림을 한 번 보내주도록 한다. 이 경우, 현재의 값을 newKey에 담아서 보낸다
    • .prior : 변경이 일어날 때, 변경 전후로 알림을 별도로 보낸다.
import Foundation

// observe 하려는 프로퍼티에 @objc attribute와 dynamic modifier를 추가해야 한다.
class Address: NSObject {
    @objc dynamic var town: String
    
    init(town: String) {
        self.town = town
    }
}

// observer 필요 : observe 하려는 프로퍼티가 변경되는지 봐야하기 때문
// observer 추가 : \.town
// 변경사항이 필요하지 않으면 options 안 주면 됨 -> nil이 출력됨
var address = Address(town: "Seoul")

address.observe(\.town, options: [.old, .new, .initial]) { (object, change) in print(change.oldValue, change.newValue)
    print("************************")
}


// address의 town 값 변경
address.town = "Jeju"
address.town = "London"
address.town = "Paris"

/* 결과
< .old, .new, .initial 일 때>
nil Optional("Seoul")
************************
Optional("Seoul") Optional("Jeju")
************************
Optional("Jeju") Optional("London")
************************
Optional("London") Optional("Paris")
************************

< .old, .new, .prior 일 때>
Optional("Seoul") nil
************************
Optional("Seoul") Optional("Jeju")
************************
Optional("Jeju") nil
************************
Optional("Jeju") Optional("London")
************************
Optional("London") nil
************************
Optional("London") Optional("Paris")
************************
*/

장점

  • 프로퍼티가 변경될 때마다 알람을 보내도록 자체 스키마를 구현할 필요가 없다
  • 객체의 구현을 변경하지 않고 외부에서 내부 객체의 상태 변화에 대응할 수 있다
  • 관찰된 프로퍼티의 이전값(oldValue)과 최신값(newValue)를 제공한다

단점

  • NSObject를 상속받는 객체에서만 사용이 가능하다
  • Objective-C 런타임에 의존하기 때문에 순수한 Swift 코드에서는 좋지 않다

📝 참고

@Hminchae
Copy link
Member

Hminchae commented Sep 7, 2023

KVO(Key-Value Observing)

  • 특정 키 값의 변화를 감지하고 알려주는 코코아 프로그래밍 패턴
  • 모델과 뷰처럼 앱의 논리적으로 분리되어 있는 사이 간 변경 사항을 전달하는데 유용하게 쓰임
  • property observers(willset , didSet)과 아주 유사한데 KVO는 타입 정의 밖에서 observe를 추가한다는 점이 다름
  • Objective-c 런타임에 의존 하고 있기 때문에, NSObject를 상속받기 위해 @objc 를 반드시 붙여줘야 한다. 특히 KVO는 속성 각각에 @objc dynamic 을 붙여줘야 함

예시코드

class SomeClass: NSObject {
  @objc dynamic var value: String = ""
}

let someObject = SomeClass()

someObject.observe(\.value) { (object, change) in
  print("SomeClass object value changed to \(object.value)")
}

someObject.value = "test"  // TEST

사용 장점

  • 두 객체 사이의 정보를 맞춰주는 것이 쉬움
  • new/old value를 쉽게 얻을 수 있음
  • key path로 옵저빙하기 때문에 nested objects도 옵저빙이 가능함

사용 단점

  • NSObject를 상속받는 객체에서만 사용이 가능함
  • dealloc될 때 옵저버를 지워줘야 함
  • 많은 value를 감지할 때는 많은 조건문이 필요

📝참조

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Swift Swift CS 개념 공부
Projects
None yet
Development

No branches or pull requests

4 participants