Where who wants to meet someone

[1주차] 2. KVO 동작 방식에 대해 설명하시오 본문

Apple Developer/면접 스터디

[1주차] 2. KVO 동작 방식에 대해 설명하시오

Lust3r 2023. 7. 3. 22:28
728x90

  1. Optional이란 무엇인지 설명하시오.
  2. KVO 동작 방식에 대해 설명하시오.
  3. stackView의 장점과 단점에 대해서 설명하시오.

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

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

다른 개체의 속성에 대한 변경 사항을 개체에 알리는 방법

 

Overview

Key-value observing은다른 개체의 속성 변경에 대해개체에 알리는데 사용하는 Cocoa 프로그래밍 패턴이다.

Model과 View 사이와 같이 앱에서논리적으로 분리된 부분 간에 변경 사항을 전달하는 데 유용하다.

NSObject에서 상속받은 클래스에서만 키-값 관찰을 사용할 수 있다.

 

Why? NSObject?

KVO는Objective-C runtime의 메커니즘을 사용하여 속성 변경을 감지한다.

이를 위해 KVO는객체의 클래스 구조와 메모리 레이아웃에 대한 내부적인 정보에 접근해야 함.

NSObject클래스는Objective-C의 기본 클래스로서 NSObject를 상속받은 클래스들은 Objective-C runtime의 기능과 메커니즘을 활용할 수있음.

 

이 runtime은 클래스와 객체에 대한 메타데이터를 관리하고, 메서드 실행, 프로퍼티 접근, 클래스 상속 등의 기능을 지원함.

KVO는 속성 변경을 감지하기 위해 해당 객체의 클래스에 동적으로 생성된 중간 클래스(Intermediate Class)를 생성하고, 이 중간 클래스를 통해 객체의 속성 변경을 관찰함.

 

Swift에서는NSObjectProtocol을 준수하는 클래스에서도 KVO를 사용할 수 있다.

NSObject를 상속받지 않은 클래스에서 KVO를 사용하려면 NSObjectProtocol을 준수하는 클래스로 감싸거나 커스텀 KVO 구현을 해야할 수 있음.

 

더 나아가 애플 Objective-C 문서의NSKeyValueObserving문서에서 더 많은 내용을 얻을 수 있다.

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

단순 특성, 일대일 및 일대다 관계를 포함한 모든 개체 속성을 관찰할 수 있다

일대다 관계의 옵저버는 변경 유형과 변경에 관련된 개체에 대한 정보를 받는다.

NSObject는 모든 객체에 대한 자동 관찰 기능을 제공하는 NSKeyValueObserving 프로토콜의 구현을 제공한다.

이 프로토콜의 방법을 사용하여 자동 관찰자 알림을 비활성화하고 수동 알림을 구현하여 알림을 더욱 구체화할 수 있다.

 

토픽으로 Change Notification, Registering for Observation, Notifying Observers of Changes 등 기능을 보여주는데,

이런 기능을 사용할 수 있는 프로토콜을 구현하게 해주는 것이NSObject이기 때문에 이를 상속받은 클래스에서만 사용할 수 있는 것이다.

 

Annotate a Property for Key-Value Observing(키-값 관찰을 위해 속성에 주석 달기)

@objc속성과dynamicmodifier를 모두 사용하여 키-값 관찰을 통해 관찰하려는 속성을 표시한다.

아래 예제에서는 관찰할 수 있는 myDate 프로퍼티를 사용하여 MyObjectToObserve 클래스를 정의한다.

class MyObjectToObserve: NSObject {
	@objc dynamic var myDate = NSDate(timeIntervalSince1970: 0) // 1970
    func updateDate() {
    	myDate = myDate.addingTimeInterval(Double(2 << 30)) // Adds about 68 years.
    }
}

 

What? dynamic?

dynamic도 역시 Objective-C와 연관된 키워드이다.

런타임에 결정되는 동적 디스패치, 컴파일타임에 결정되는 정적 디스패치가 있다는 것을 바탕으로 Objective-C는 Objective-C 런타임을, Swift는 Swift 런타임을 사용하는데 전자는 동적 디스패치만을 사용하지만, 후자는 다른 선택이 없으면 동적 디스패치를 선택한다고 한다.(참조: https://zeddios.tistory.com/296)

 

즉 여기서의 dynamic은 Swift 런타임 대신 Objective-C 런타임을 쓴다는 의미.

 

Compile time?

컴파일러에 의해 수행되는 동작, 성공적으로 컴파일되기 위해서 소스 코드가 충족해야 하는 프로그래밍 언어 요구사항 또는 컴파일 동안 추론될 수 있는 프로그램의 속성을 나타냄.

 

컴파일 타임은 링크 타임(하나 이상의 컴파일된 파일들이 같이 합쳐질 때)과 런타임(프로그램이 실행되었을 때)전에 발생한다.

 

Runtime?

CS에서 컴퓨터 프로그램이 실행되고 있는 동안의 동작을 의미. 런타임이라는 용어는 컴퓨터 언어 안에 쓰인 프로그램을 관리하기 위해, 특정한 컴파일러나 가상 머신이 사용하는 기본 코드의 라이브러리나 프로그램을 통틀어 런타임 라이브러리라고도 일컫는다.

 

정리하자면 위의 코드에서

@objc dynamic var myDate = NSDate(timeIntervalSince1970: 0) // 1970

이 부분이 의미하는 것은, 해당 프로퍼티를 Objective-C 런타임을 사용하여 동적 디스패치를 사용할건데(@objc dynamic)

키값 관찰을 하려면 해당 클래스가 NSObject 상속을 받아야 하니 MyObjectToObserve: NSObject를 해준 것이다.

 

Define an Observer

observer 클래스의 인스턴스는 하나 이상의 속성에 대한 변경 사항에 대한 정보를 관리한다.

observer를 만들 때 관찰하려는 속성을 참조하는 키 경로로 observe(_:options:changeHandler:) 메서드를 호출하여 관찰을 시작.

 

아래 예에서 \.objectToObserve.myDate 키 경로는 MyObjectToObserve의 myDate 속성을 참조한다.

class MyObserver: NSObject {
    @objc var objectToObserve: MyObjectToObserve
    var observation: NSKeyValueObservation?
    
    init(object: MyObjectToObserve) {
    	objectToObserve = object
        super.init()
        
        observation = observe(
        	\.objectToObserve.myDate,
            options: [.old, .new]
        ) { object, change in
        	print("myDate changed from: \(change.oldValue!), updated to: \(change.newValue!)")
        }
    }
}

NSKeyValueObservedChange 인스턴스의 oldValuenewValue 속성을 사용하여 관찰 중인 속성에 대해 변경된 사항을 확인

(change.oldValue, change.newValue)

 

속성이 어떻게 변경되었는지 알 필요가 없으면 options 매개변수를 생략할 수 있다. 이 경우 newValueoldValue를 저장하지 않으므로 nil이 된다.

 

Associate the Observer with the Property to Observe

개체를 관찰자의 이니셜라이저에 전달하여 관찰하려는 속성을 observer와 연결한다.

let observed = MyObjectToObserve()
let observer = MyObserver(object: observed)

 

Respond to a Property Change

위에서 관찰한 것과 같이 키-값 관찰을 사용하도록 설정된 객체는 관찰자에게 속성 변경에 대해 알림.

아래 예제는 updateDate 메서드를 호출하여 myDate 속성을 변경하는데, 해당 메서드 호출은 observer의 change handler를 자동으로 트리거함.

observed.updateDate() // Triggers the objerver's change handler.
// Prints "myDate changed from: 1970-01-01 00:00:00 + 0000, updated to : 2038-01-19 03:14:08 +0000"

이전에 observe(_:options:changeHandler:) 설정했을 때 options 값으로 .old, .new를 주었기에 가능하다.