티스토리 뷰

728x90

Key-Value Observing

 

publisher(for:)

단일 변수의 변화를 관찰하려면?
KVO(Key-Value Observing)를 준수하는 객체의 모든 속성에 대한 게시자를 제공합니다.
ObservableObject 프로토콜은 여러 변수가 변경될 수 있는 경우를 처리합니다.

KVO는 Objective-C의 필수 구성 요소였고,
Foundation, UIKit 및 AppKit 클래스 대부분의 프로퍼티는 KVO를 준수합니다.
따라서, KVO를 사용하여 변화를 관찰할 수 있습니다.

KVO를 준수하는 프로퍼티를 관찰하는 방법 (OperationQueue를 이용)

import Combine
import Foundation

let queue = OperationQueue()

let subscription = queue.publisher(for: \.operationCount)
    .sink {
        print("Outstanding operations in queue: \($0)")
    }​

 

KVO를 준수하는 프로퍼티 세팅 및 subscribe

- NSObject를 채택하는 class 
- 프로퍼티 앞에 @objc dynamic 키워드 추가.

아래 예시 코드 참고.
// 1
class TestObject: NSObject {
    // 2
    @objc dynamic var integerProperty: Int = 0
}

let obj = TestObject()
// 3
let subscription = obj.publisher(for: \.integerProperty)
    .sink {
        print("integerProperty changes to \($0)")
    }
// 4
obj.integerProperty = 100
obj.integerProperty = 200

//integerProperty changes to 0
//integerProperty changes to 100
//integerProperty changes to 200​

1. NSObject 프로토콜을 준수하는 class를 만듭니다.
2. 관찰하고 싶은 프로퍼티 앞에 @objc dynamic 키워드를 붙여줍니다.
3. 변수 integerProperty를 관찰하는 게시자를 subscription 상수로 만듭니다.
4. 프로퍼티를 업데이트 해서 값을 관찰하는걸 확인합니다.


위에도 언급했지만, KVO는 Objective-C 기능이며, Objective-C에 연결된 모든 Swift 유형에서 잘 작동합니다.

+ 추가 테스트
class TestObject: NSObject {
    
    @objc dynamic var integerProperty: Int = 0
    @objc dynamic var stringProperty: String = ""  //추가
    @objc dynamic var arrayProperty: [Float] = []  //추가
    
}

let obj = TestObject()

let subscription = obj.publisher(for: \.integerProperty)
    .sink {
        print("integerProperty changes to \($0)")
    }

obj.integerProperty = 100
obj.integerProperty = 200

//추가
let subscription2 = obj.publisher(for: \.stringProperty)
    .sink {
        print("stringProperty changes to \($0)")
    }

let subscription3 = obj.publisher(for: \.arrayProperty)
    .sink {
        print("arrayProperty changes to \($0)")
    }

obj.stringProperty = "Hello"
obj.arrayProperty = [1.0]
obj.stringProperty = "World"
obj.arrayProperty = [1.0, 2.0]

//integerProperty changes to 0
//integerProperty changes to 100
//integerProperty changes to 200
//stringProperty changes to
//arrayProperty changes to []
//stringProperty changes to Hello
//arrayProperty changes to [1.0]
//stringProperty changes to World
//arrayProperty changes to [1.0, 2.0]


debug area를 보면 초기값과 변경된 값들이 나오는걸 확인할 수 있습니다.

 

 

 

publisher(for:options:)

options 파라미터에 .initial, .prior, .old, .new 4가지 값들이 있습니다.

.initial: 초기값을 방출
• .prior: 값이 변경될 때 '이전 값' 과 '새로운 값' 방출

1. 초기값을 제외하고 싶다면?

options: [] 
let subscription2 = obj.publisher(for: \.stringProperty, options: [])
    .sink {
        print("stringProperty changes to \($0)")
    }
    
//초기값 제외
//stringProperty changes to Hello
//stringProperty changes to World


2. 값이 바뀔때 이전값을 확인하고 싶다면?

options: [.prior]

let subscription2 = obj.publisher(for: \.stringProperty, options: [.prior])
    .sink {
        print("stringProperty changes to \($0)")
    }
    
//stringProperty changes to 
//stringProperty changes to Hello
//stringProperty changes to Hello
//stringProperty changes to World

 

 

 


위 방법 보다 더 간단하게 값을 관찰할 수 있는 방법이 있습니다. 

 

ObservableObject

Combine의 ObservableObject 프로토콜은 NSObject에서 파생된 객체뿐만 아니라 Swift 객체에서 작동합니다.

사용법
1. class에 ObservableObject 프로토콜 채택
2. 프로퍼티 앞에 @Published 키워드를 붙이면 끝


import Combine
import Foundation

class MonitorObject: ObservableObject {
    @Published var someProperty = false
    @Published var someOtherProperty = ""
}

let object = MonitorObject()
let subscription = object.objectWillChange.sink { 
    print("object will change")
}

object.someProperty = true
object.someOtherProperty = "Hello World"

//object will change
//object will change​

  
어떤값이 변경되었는지 알수는 없지만, 값이 변경될때를 알기 때문에 UI업데이트할때 유용하게 쓰일것 같습니다.
(SwiftUI와 잘 맞게 설계되었다고 나와있음)
728x90

'iOS' 카테고리의 다른 글

[iOS] Camera 설정 - AVCaptureSession(feat. 카메라 권한 설정)  (0) 2023.02.26
[Combine] Chapter13 : Resource Management  (0) 2023.01.19
[Combine] Chapter11 : Timers  (0) 2023.01.08
[Combine] Chapter10 : Debugging  (0) 2023.01.03
UIView vs CALayer  (0) 2022.12.28