ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [iOS] KVO λž€? (Key Value Observing)
    iOS/πŸ€– App 2021. 5. 22. 19:55

    1μ°¨ μˆ˜μ •: 2021/06/08

     

    μ•ˆλ…•ν•˜μ„Έμš”. 이번 μ‹œκ°„μ—λŠ” KVO 에 λŒ€ν•΄ κ³΅λΆ€ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€πŸΆ

     

    Observing μ΄λΌλŠ” λ‹¨μ–΄λŠ” κ°μ‹œν•œλ‹€λŠ” 의미λ₯Ό 가지고 있죠. κ·Έλ ‡λ‹€λ©΄ KVOλŠ” 무엇을 κ°μ‹œν•˜λŠ” κ²ƒμΌκΉŒμš”?

     

    λ°”λ‘œ λ‹€λ₯Έ 였브젝트의 μ†μ„±μž…λ‹ˆλ‹€.

     

    KVO λŠ” B λΌλŠ” 였브젝트의 속성 값이 λ³€κ²½λ˜μ—ˆμ„ λ•Œ,  A λΌλŠ” μ˜€λΈŒμ νŠΈκ°€ μ•Œκ²Œ λ˜λŠ” κ²ƒμž…λ‹ˆλ‹€.


     

     

    KVOλŠ” λͺ¨λΈ λ ˆμ΄μ–΄μ™€ λ·° λ ˆμ΄μ–΄ 같이 λ…Όλ¦¬μ μœΌλ‘œ λΆ„λ¦¬λ˜μ–΄ μžˆλŠ” μ˜€λΈŒμ νŠΈκ°„ λ©”μ‹œμ§€ 전달에 μœ μš©ν•©λ‹ˆλ‹€.

     

    예λ₯Ό λ“€μ–΄ λͺ¨λΈ λ ˆμ΄μ–΄μ—μ„œ 값이 λ³€κ²½λ˜λ©΄, κ°μ‹œν•˜κ³  있던 λ·° λ ˆμ΄μ–΄μ—κ²Œ μ „λ‹¬λ˜μ–΄ 변경에 λŒ€μ‘ν•  수 μžˆλŠ” κ²ƒμž…λ‹ˆλ‹€.

     

    λ‚˜μ€‘μ— 봐도 이해할 수 있게 μ œκ°€ λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€.


     

    κ°μ‹œν•  속성에 ν‘œμ‹œν•˜κΈ°

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

     

    κ°μ‹œν•  수 μžˆλŠ” ν΄λž˜μŠ€μ—λŠ” 쑰건이 ν•˜λ‚˜ μžˆλŠ”λ°, λ°”λ‘œ NSObject λ₯Ό μƒμ†ν•œ ν΄λž˜μŠ€μ—¬μ•Ό ν•œλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€.

     

    그리고 KVOλ₯Ό μˆ˜ν–‰ν•˜λ €λ©΄ κ°μ‹œν•  속성에 @objc μ–΄νŠΈλ¦¬λ·°νŠΈμ™€  dynamic λͺ¨λ””νŒŒμ΄μ–΄λ₯Ό λΆ™μ—¬μ£Όμ–΄μ•Ό ν•©λ‹ˆλ‹€.

     

    μœ„ μ½”λ“œμ—μ„œλŠ” myDate 라고 ν•˜λŠ” λ³€μˆ˜κ°€ κ°μ‹œλ₯Ό ν•  수 μžˆλŠ” 속성이 λ©λ‹ˆλ‹€.


     

    κ°μ‹œμž μ •μ˜ν•˜κΈ°

    κ°μ‹œμž 역할을 ν•˜λŠ” μΈμŠ€ν„΄μŠ€λŠ” ν•œ 개 μ΄μƒμ˜ 속성을 κ°μ‹œν•  수 μžˆμŠ΅λ‹ˆλ‹€.

     

    κ°μ‹œλ₯Ό μΆ”κ°€ν•˜λŠ” 법은 κ°μ‹œμž μΈμŠ€ν„΄μŠ€μ—μ„œ observe(_:options:changeHandler:) λ©”μ„œλ“œμ— κ°μ‹œλ₯Ό μ›ν•˜λŠ” μ†μ„±μ˜ key-path λ₯Ό μ „λ‹¬ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. ν˜ΈμΆœν•˜λŠ” μ‹œμ λΆ€ν„° μ†μ„±μ˜ κ°’ 변경을 κ°μ‹œν•©λ‹ˆλ‹€.

     

    observe(_:options:changeHandler:) λ©”μ„œλ“œμ˜ μ‚¬μš©μ„ μ•„λž˜ μ½”λ“œμ—μ„œ μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

     

    첫번째 νŒŒλΌλ―Έν„°μΈ \.objectToObserve.myDate λŠ” objectToObserve μΈμŠ€ν„΄μŠ€μ˜ myDate μ†μ„±μ˜ key path μž…λ‹ˆλ‹€.

     

    λ‘λ²ˆμ§Έ νŒŒλΌλ―Έν„°μΈ [.old, .new] λŠ” λ§ˆμ§€λ§‰ 트레일링 ν΄λ‘œμ €μ—μ„œ oldValue 와 newValue λΌλŠ” 속성λ₯Ό μ‚¬μš©μ—¬λΆ€ κ²°μ •ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

     

    μ—¬κΈ°μ„œ oldValue λŠ” λ³€κ²½ μ§μ „μ˜ μ†μ„±μ˜ 값이고, newValueλŠ” λ³€κ²½ 이후 μ†μ„±μ˜ κ°’μž…λ‹ˆλ‹€.

     

    μ„Έλ²ˆμ§Έ νŒŒλΌλ―Έν„°λŠ” ν΄λ‘œμ €λ‘œ, κ°’ λ³€κ²½μ‹œ μˆ˜ν–‰ν•  λ™μž‘μ„ μ •μ˜ν•˜μ—¬ μ „λ‹¬ν•©λ‹ˆλ‹€.

     

    β—οΈμ „λ‹¬ν•œ ν΄λ‘œμ €λŠ” κ°μ‹œμ€‘μΈ μ†μ„±μ˜ 값이 λ³€κ²½λ λ•Œ ν˜ΈμΆœλ©λ‹ˆλ‹€.

    호좜될 λ•Œ 이 ν΄λ‘œμ €μ—λŠ” 두 개의 νŒŒλΌλ―Έν„°μ— 값이 μ „λ‹¬λ˜λŠ”λ°, 첫번째 νŒŒλΌλ―Έν„°μ— κ°μ‹œμž 역할을 ν•˜λŠ” 였브젝트 (_KeyValueCodingAndObserving ν”„λ‘œν† μ½œ νƒ€μž…) κ°€ μ „λ‹¬λ˜κ³ ,

     

    λ‘λ²ˆμ§Έ νŒŒλΌλ―Έν„°μ— NSKeyValueObservedChange<Value> νƒ€μž…μ˜ 값이 λ“€μ–΄μ˜€λŠ”λ°, 이 κ°’μ—μ„œ oldValue 와 newValue 에 μ ‘κ·Όν•  수 μžˆμŠ΅λ‹ˆλ‹€.

     

    λ§Œμ•½ observe(_:options:changeHandler:)  λ©”μ„œλ“œμ˜ options νŒŒλΌλ―Έν„°μ— 아무것도 μ „λ‹¬λ˜μ§€ μ•ŠλŠ”λ‹€λ©΄, 이 값은 nil 둜 μ΄ˆκΈ°ν™” λ©λ‹ˆλ‹€.

     

    μ•„λž˜ μ½”λ“œμ—μ„œλŠ” ν΄λ‘œμ €μ—μ„œ 각각 object 와 change λ₯Ό argument label 둜 μ‚¬μš©ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

     

    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!)")
            }
        }
    }

     

    Property Observer 와 λ‹€λ₯Έ 점은? πŸ€”

     

    Property Observer λŠ” 값을 κ°μ‹œν•œλ‹€λŠ” κ°œλ…μ€ μœ μ‚¬ν•˜μ§€λ§Œ,

    Property Observer 의 경우 ν•Έλ“€λŸ¬ μžμ²΄κ°€ κ°μ‹œλ˜λŠ” 속성과 같은 μœ„μΉ˜μ— μ„ μ–Έλ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

     

    λ°˜λ©΄μ— KVO λŠ” ν•Έλ“€λŸ¬κ°€ κ°μ‹œν•˜λŠ” μ˜€λΈŒμ νŠΈμ— μ •μ˜λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

    " KVO is for adding observers outside of the type definition."

     

    μœ„ μ½”λ“œ( MyObserver) μ—μ„œλŠ” κ°μ‹œλ‹Ήν•˜λŠ” 였브젝트의 μ°Έμ‘°λ₯Ό κ°μ‹œν•˜λŠ” μ˜€λΈŒμ νŠΈκ°€ 가지고 μžˆμŠ΅λ‹ˆλ‹€.

    UML μ—μ„œ 단방ν–₯ 연관관계λ₯Ό ν‘œν˜„

     

    λ°˜λ©΄μ— Property Observe r둜 μœ„μ˜ μ½”λ“œμ™€ 같이 λ™μž‘ν•˜κ²Œ ν•˜λ €λ©΄ κ°μ‹œλ‹Ήν•˜λŠ” μ˜€λΈŒμ νŠΈκ°€ κ°μ‹œν•˜λŠ” 였브젝트의 μ°Έμ‘°λ₯Ό 가지고 μžˆκ²Œλ©λ‹ˆλ‹€.  

     

    ν•Έλ“€λŸ¬ μžμ²΄κ°€ κ°μ‹œ λ‹Ήν•˜λŠ” μ˜€λΈŒμ νŠΈμ—μ„œ κ΅¬ν˜„λ˜μ–΄μ•Ό ν•˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€. 이 뢀뢄이 λ°˜λŒ€μž…λ‹ˆλ‹€.

     

    κ΅¬ν˜„μ— 따라 λ¬Όλ‘  이런 관계가 생기지 μ•Šμ„ 수 μžˆμ§€λ§Œ, μœ„μ˜ μ½”λ“œμ™€ 같이 κ΅¬ν˜„ν•˜λŠ” μƒν™©μ—μ„œλŠ” μ•„λž˜μ™€ 같은 관계가 μƒκΉλ‹ˆλ‹€.

    μ΄λ ‡κ²Œ μƒκ°ν•˜λ©΄ κ°μ‹œν•œλ‹€κ³  λ³΄κΈ°λŠ” μ–΄λ €μšΈ 것 κ°™μŠ΅λ‹ˆλ‹€.

    μ΄λ‘œμ„œ iOSμ—μ„œ λ‹€λ₯Έ μ˜€λΈŒμ νŠΈμ—κ²Œ κ°’μ˜ 변경을 μ•Œλ €μ£ΌλŠ” 방법 쀑 ν•˜λ‚˜μΈ KVOλ₯Ό 닀루어 λ³΄μ•˜μŠ΅λ‹ˆλ‹€.

     

    RxSwift λ₯Ό 배우기 전이라면 이 λ°©λ²•μœΌλ‘œ MVVM μ—μ„œ λ·°λͺ¨λΈκ³Ό 뷰의 바인딩을 κ΅¬ν˜„ν•  수 μžˆμ„ 것 κ°™μŠ΅λ‹ˆλ‹€.


     

    의문점

    속성이 μ°Έμ‘° ν˜•μ‹μΌ λ•Œ, μ°Έμ‘° ν˜•μ‹ λ‚΄λΆ€μ˜ 속성 변경에도 λ°˜μ‘ν•˜λŠ”κ°€?

     

    A: μ•„λ‹™λ‹ˆλ‹€. μ°Έμ‘° ν˜•μ‹μ˜ 값은 μ£Όμ†Œ μ΄λ―€λ‘œ μΈμŠ€ν„΄μŠ€κ°€ 변경될 λ•Œ λ°˜μ‘ν•©λ‹ˆλ‹€.

     

    κ΄€λ ¨ κΈ€ : [Swift] κ°’νƒ€μž…κ³Ό μ°Έμ‘°νƒ€μž… ( Value Type vs Reference Type )

     

     

     

    끝!


    πŸ€–πŸŸ’[우짱의 iOS λΈ”λ‘œκ·Έ]πŸ”΅πŸ’»

    iOSλ₯Ό κ³΅λΆ€ν•˜λ©΄μ„œ 배운 λ‚΄μš©μ„ κΈ°λ‘ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

     

     

    참고 자료 1: https://developer.apple.com/documentation/swift/cocoa_design_patterns/using_key-value_observing_in_swift

    참고 자료 2:https://www.hackingwithswift.com/example-code/language/what-is-key-value-observing

    λŒ“κΈ€

μ–΄μ œλ³΄λ‹€ λ°œμ „ν•œ λ‚˜