๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐ŸŽ iOS/iOS

[iOS ๋ฉด์ ‘์งˆ๋ฌธ] KVO๋ž€?

by Fomagran ๐Ÿ’ป 2020. 12. 29.
728x90
๋ฐ˜์‘ํ˜•

์•ˆ๋…•ํ•˜์„ธ์š” Foma ์ž…๋‹ˆ๋‹ค.

 

์˜ค๋Š˜์€ iOS๋ฉด์ ‘์งˆ๋ฌธ์— ์ž์ฃผ ๋‚˜์˜ค๋Š” KVO์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.


KVO๋ž€?

๊ณต์‹ ๋ฌธ์„œ์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด  ์ •์˜๋˜์–ด์žˆ์Šต๋‹ˆ๋‹ค.

ํ•ด์„ํ•ด๋ณด๋ฉด KVO๋Š” Key Value Observing์˜ ์ค„์ž„๋ง์ด๊ณ  ๋‹ค๋ฅธ ๊ฐ์ฒด์˜ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ์•Œ๋ ค์ฃผ๋Š” ์ฝ”์ฝ”์•„ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ํŒจํ„ด์ด๋ผ๊ณ  ํ•˜๋„ค์š”.

 

ํ”„๋กœํผํ‹ฐ ์˜ต์ €๋ฒ„ willSet๊ณผ disSet์ด๋ž‘ ์œ ์‚ฌํ•˜์ง€๋งŒ ์™ธ๋ถ€์— ๊ด€์ฐฐ์ž๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

 

๊ฐ„๋‹จํ•˜๊ฒŒ ์„ค๋ช…๋“œ๋ฆฌ๋ฉด ๊ด€์ฐฐํ•˜๊ณ  ์‹ถ์€ ๊ฐ์ฒด์— ์˜ต์ €๋ฒ„๋ฅผ ๋‹ฌ๊ณ  ๊ทธ ๊ฐ’์ด ๋ณ€ํ• ๋•Œ ๋ฐ”๋€Œ๊ธฐ์ „ ๊ฐ’์ด๋ž‘ ๋ฐ”๋€๊ฐ’์„ ์•Œ๋ ค์ฃผ๋Š” ๊ฒƒ์ด๋ผ๊ณ  ๋ณด๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

์‚ฌ์šฉ ๋ฐฉ๋ฒ•

KVO๋Š” Objective-C ๋Ÿฐํƒ€์ž„์— ์˜์กดํ•ฉ๋‹ˆ๋‹ค. ๊ณ ๋กœ ์•ž์— @objc dynamic๊ฐ€ ๋ถ™์€ NSObject Class๋กœ ์ƒ์„ฑํ•ด์ฃผ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

 

๋จผ์ € Swift 4 ์ด์ „์—๋Š” ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜์˜€๋Š”์ง€๋ถ€ํ„ฐ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

์•„๋ž˜์™€ ๊ฐ™์ด Person ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๊ณ 

 

1
2
3
4
5
import Foundation
 
@objc class Person:NSObject {
    @objc dynamic var name = "Fomagran"
}

Person์„ ๊ด€์ฐฐํ•˜๋Š” Observer๋ฅผ ๋”ฐ๋กœ ๋งŒ๋“ค์–ด์ค€ ๋’ค func observeValue๋„ ๋”ฐ๋กœ override ํ•จ์ˆ˜๋กœ ๊ตฌํ˜„ํ•ด์ค˜์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class PersonObserver:NSObject {
 
    var person:Person
    
    init(withPerson:Person) {
        self.person = withPerson
        super.init()
        self.person.addObserver(self, forKeyPath: #keyPath(Person.name), options: .new, context: &myContext)
    }
    
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if context == &myContext {
            guard let change = change else { return }
            print("\(person.name) has changed \(change[.newKey] ?? "")")
        }
    }
}

์•„๋ž˜์ฒ˜๋Ÿผ Person ์ธ์Šคํ„ด์Šค์™€ PersonObsever ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค์–ด์ค€ ๋’ค person์˜ ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•˜๊ฒŒ ๋˜๋ฉด

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import UIKit
 
class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let fomagran = Person()
        let observer = PersonObserver(withPerson:fomagran)
        
        fomagran.name = "Khalid"
        fomagran.name = "Young"
        
    }
    
}

์•„๋ž˜์™€ ๊ฐ™์ด ์›๋ž˜์˜ ์ด๋ฆ„์„ ๊ด€์ฐฐํ•˜๋ฉด์„œ ์›๋ž˜์˜ ์ด๋ฆ„๊ณผ ๋ฐ”๋€ ์ด๋ฆ„์„ ์ถœ๋ ฅํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ Swift4๋ถ€ํ„ฐ๋Š” Person ํด๋ž˜์Šค๋งŒ ๋งŒ๋“ค์–ด์ฃผ๊ณ  PersonObserver๋ฅผ ๋”ฐ๋กœ ๊ตฌํ˜„ํ•ด์ฃผ์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค.

 

๋Œ€์‹  ViewController์—์„œ ์•„๋ž˜์™€ ๊ฐ™์ด Observation์„ ๋งŒ๋“ค์–ด์ฃผ๊ณ  ์ธ์Šคํ„ด์Šค์— observe ๋ฉ”์†Œ๋“œ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•ด์ฃผ๋ฉด

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import UIKit
 
class ViewController: UIViewController {
    
    var nameObservation: NSKeyValueObservation?
    let fomagran = Person()
    
    override func viewDidLoad() {
        super.viewDidLoad()
 
        nameObservation = fomagran.observe(\Person.name, options: [.old,.new,.initial]) { (person, name) in
            print("\(name.oldValue ?? "") changed name to \(name.newValue ?? "")")
        }
        fomagran.name = "Young"
    }

์•„๋ž˜์™€ ๊ฐ™์ด ์ •์ƒ์ ์œผ๋กœ ๊ด€์ฐฐํ•˜๊ณ  ์›๋ž˜์˜ ์ด๋ฆ„๊ณผ ๋ฐ”๋€ ์ด๋ฆ„์„ ์ถœ๋ ฅํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

๋˜ํ•œ ๊ด€์ฐฐํ•˜๋Š” ๊ฒƒ์„ ํ•ด์ œ์‹œ์ผœ์ฃผ์ง€ ์•Š์œผ๋ฉด ๊ณ„์† ๊ด€์ฐฐํ•˜๊ฒŒ ๋˜๋ฏ€๋กœ viewWillAppear ๋ฉ”์†Œ๋“œ๋ฅผ ํ™œ์šฉํ•ด ํ•ด์ œ์‹œ์ผœ์ฃผ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

 

1
2
3
 override func viewWillDisappear(_ animated: Bool) {
        nameObservation?.invalidate()
    }

 

 

์ด๋ ‡๊ฒŒ ์˜ค๋Š˜์€ KVO์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์•˜๋Š”๋ฐ์š”.

 

์ •๋ง ๊ฐ„๋‹จํ•˜๊ฒŒ ์–ด๋–ค ๊ฒƒ์ธ์ง€๋งŒ ์•Œ์•„๋ณด์•„์„œ ๋ถ€์กฑํ•˜์ง€๋งŒ ๋” ๊นŠ์ด ๊ณต๋ถ€ํ•˜๋ฉด ํ™œ์šฉํ•  ๋ฐฉ๋ฒ•์ด ์•„์ฃผ ๋งŽ์„ ๊ฑฐ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

๋งŒ์•ฝ ํ‹€๋ฆฐ์ ์ด ์žˆ๊ฑฐ๋‚˜ ๋ถ€์กฑํ•œ ์ ์ด ์žˆ๋‹ค๋ฉด ๋Œ“๊ธ€๋กœ ์•Œ๋ ค์ฃผ์„ธ์š”!

728x90
๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€