prosource

KVO(Key-Value Observation)는 Swift에서 사용할 수 있습니까?

probook 2023. 4. 23. 10:35
반응형

KVO(Key-Value Observation)는 Swift에서 사용할 수 있습니까?

그렇다면, Objective-C에서 키 값 관찰을 사용할 때 달리 나타나지 않았던 주요 차이점이 있습니까?

KVVO를 사용하여 KVO swift 용 지 만 , 있 할 you수 can for swift k k only사 but use,에 in서vo는vo you can swiftdynamic의 속의 속성NSObject서브 클래스서브클래스 Consider that you wanted to observe the 당신이 관찰하기를 원했다고 생각하세요.bar의의 재산Foo class. In Swift 4, specify 클래스.스위프트 4 서bar as ~하듯이dynamic your의 NSObject★★★★★★★★★★★★★★★★★★:

class Foo: NSObject {
    @objc dynamic var bar = 0
}

할 수 .bar소유물.Swift 4 및 Swift 3.2에서는 "Swift의 주요 가치 관찰 사용:

class MyObject {
    private var token: NSKeyValueObservation

    var objectToObserve = Foo()

    init() {
        token = objectToObserve.observe(\.bar) { [weak self] object, change in  // the `[weak self]` is to avoid strong reference cycle; obviously, if you don't reference `self` in the closure, then `[weak self]` is not needed
            print("bar property is now \(object.bar)")
        }
    }
}

(「」: 「Swift 4」)를한 키 하게 되었습니다.\.bar의 키 패스입니다.bar★★★★★★★★★★★★★★★★★★★★★★★★★」token됩니다).또, 「」, 「이러다」, 「이러다」를 호출할 .super키가 일치하지 않을 경우 구현합니다.닫힘은 이 특정 옵서버가 호출되었을 때만 호출됩니다.자세한 내용은 WWDC 2017 비디오 "What's New in Foundation"을 참조하십시오.

Swift 3에서는, 이것을 관찰하는 것은 조금 복잡하지만, Objective-C의 경우와 매우 유사합니다. ,, 객, 고, 님, 님, namely를 구현합니다.observeValue(forKeyPath keyPath:, of object:, change:, context:)맥락을 (가) 의 맥락을 있다(가)super가 관찰을 후 (하거나 (b) 그것을 (b) 하다.super .그리고 적절한 때에 관찰자로서의 자신을 배제하는 것을 잊지 마세요.예를 들어, 옵서버가 할당 해제되었을 때 옵서버를 삭제할 수 있습니다.

Swift 3의 경우:

class MyObject: NSObject {
    private var observerContext = 0

    var objectToObserve = Foo()

    override init() {
        super.init()

        objectToObserve.addObserver(self, forKeyPath: #keyPath(Foo.bar), options: [.new, .old], context: &observerContext)
    }

    deinit {
        objectToObserve.removeObserver(self, forKeyPath: #keyPath(Foo.bar), context: &observerContext)
    }

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        guard context == &observerContext else {
            super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
            return
        }

        // do something upon notification of the observed object

        print("\(keyPath): \(change?[.newKey])")
    }

}

관찰할 수 있는 속성은 Objective-C에서 나타낼 수 있는 속성뿐입니다. 제네릭, Swift는 관찰할 수 .struct Swift ™ 、 Swiftenum종류 등

Swift 2 구현에 대한 자세한 내용은 아래 원래 답변을 참조하십시오.


「 」의 dynamicKVO를 하여 KVO를 하기 위한 NSObject하위 분류는 코코아Objective-C와 함께 스위프트 사용 가이드의 코코아 설계 협약 채택 장의 주요 가치 관찰 섹션에 설명되어 있습니다.

키 값 관찰은 다른 개체의 지정된 속성에 대한 변경을 개체에 알릴 수 있는 메커니즘입니다.키값을 사용할 수 는 Swift 클래스에서 됩니다.NSObject이 세 단계를 사용하여 Swift에서 주요 가치 관찰을 구현할 수 있습니다.

  1. , 그럼 여기에다가 더해져요.dynamic관찰할 속성의 한정자를 지정합니다. 것은, 「」를 참조해 주세요.dynamic, 「다이나믹 디스패치의 필요」를 참조해 주세요.

    class MyObjectToObserve: NSObject {
        dynamic var myDate = NSDate()
        func updateDate() {
            myDate = NSDate()
        }
    }
    
  2. 글로벌 컨텍스트 변수를 만듭니다.

    private var myContext = 0
    
  3. 하고, 「」를 .observeValueForKeyPath:ofObject:change:context:, 방법, 방법에서 합니다.deinit.

    class MyObserver: NSObject {
        var objectToObserve = MyObjectToObserve()
        override init() {
            super.init()
            objectToObserve.addObserver(self, forKeyPath: "myDate", options: .New, context: &myContext)
        }
    
        override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
            if context == &myContext {
                if let newValue = change?[NSKeyValueChangeNewKey] {
                    print("Date changed: \(newValue)")
                }
            } else {
                super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
            }
        }
    
        deinit {
            objectToObserve.removeObserver(self, forKeyPath: "myDate", context: &myContext)
        }
    }
    

(이 KVO에 대한 설명은 이후 Swift 3용으로 수정된 Using Swift with Cocoa and Objective-C 가이드에서 삭제되었지만 여전히 이 답변의 상단에 설명된 대로 작동합니다.)


Swift는 고유의 속성 옵서버 시스템을 가지고 있지만, 그것은 자신의 속성을 관찰했을 때 실행되는 자체 코드를 지정하는 클래스용입니다.한편 KVO는 등록하여 다른 클래스의 동적 속성에 대한 변경을 관찰하도록 설계되어 있습니다.

(새로운 정보를 추가하기 위해 편집): KVO를 사용하는 것이 아니라 Combine 프레임워크를 사용하여 원하는 것을 달성할 수 있는지 여부를 고려합니다.

한마디로 이야기할 수 없군요.KVO는 항상 그렇듯이 NSObject 서브클래스에서 동작합니다.NSObject 하위 클래스가 아닌 클래스에서는 작동하지 않습니다.스위프트는 (적어도 현재) 고유의 관측 시스템을 가지고 있지 않다.

(다른 속성을 ObjC로 표시하여 KVO가 동작하도록 하는 방법에 대해서는 코멘트를 참조해 주세요).

상세한 예에 대해서는, Apple 의 메뉴얼을 참조해 주세요.

예, 아니오 모두:

  • , Swift에서 동일한 오래된 KVO API를 사용하여 Objective-C 개체를 관찰할 수 있습니다.
    할 수 있습니다.dynamicSwift에서 NSObject.
    하지만... 아니요, 스위프트의 네이티브 관측 시스템처럼 강한 타입은 아닙니다.
    Objective-C | 가치 | Objective-C | Swift | Key Value Observing

  • 아니요, 현재 임의 Swift 개체에 대한 값 관찰 시스템이 내장되어 있지 않습니다.

  • , 속성 옵저버가 내장되어 있으며, 이 옵저버는 강하게 입력되어 있습니다.
    그러나... 아니요. KVO가 아닙니다. KVO는 개체 자체의 속성을 관찰하는 것만 허용하기 때문에 중첩된 관찰("키 경로")을 지원하지 않으므로 명시적으로 구현해야 합니다.
    언어 | 스위프트 프로그래밍 언어 | 스위프트 프로그래밍 언어

  • , 명시적 값 관찰을 구현할 수 있습니다. 이러한 관찰은 강하게 입력되며 다른 개체에서 여러 핸들러를 추가할 수 있습니다. 또한 중첩/키 경로도 지원합니다.
    그러나... KVO는 관찰 가능한 속성에만 작동하므로 KVO가 아닙니다.
    이러한 값을 관찰하기 위한 라이브러리는 다음 URL에서 찾을 수 있습니다.
    - Swift - Events - KVO for Swift - KVO for Swift

네.

KVO 에서는디스패치가 에 KVO 를 추가하는 만으로 충분합니다.dynamic메서드, 속성, 첨자 또는 이니셜라이저의 한정자:

dynamic var foo = 0

dynamic됩니다.objc_msgSend

'이러다'는 게 아니라 '이러다'라는 거예요.modelModel아트리뷰트 「」를 해 주세요.name ★★★★★★★★★★★★★★★★★」state이러한 속성은 다음과 같이 관찰할 수 있습니다.

let options = NSKeyValueObservingOptions([.New, .Old, .Initial, .Prior])

model.addObserver(self, forKeyPath: "name", options: options, context: nil)
model.addObserver(self, forKeyPath: "state", options: options, context: nil)

이러한 속성을 변경하면, 다음의 콜이 트리거 됩니다.

override func observeValueForKeyPath(keyPath: String!,
    ofObject object: AnyObject!,
    change: NSDictionary!,
    context: CMutableVoidPointer) {

        println("CHANGE OBSERVED: \(change)")
}

롭의 대답 외에도롭의 대답에 더해서. That class must inherit from 해당 클래스는 다음에서 상속해야 합니다.NSObject, , and we have 3 ways to trigger property change속성 변경을 트리거하는 방법은 3가지가 있습니다.

setValue(value: AnyObject?, forKey key: String)부에서NSKeyValueCoding

class MyObjectToObserve: NSObject {
    var myDate = NSDate()
    func updateDate() {
        setValue(NSDate(), forKey: "myDate")
    }
}

willChangeValueForKey and 그리고.didChangeValueForKey부에서NSKeyValueObserving

class MyObjectToObserve: NSObject {
    var myDate = NSDate()
    func updateDate() {
        willChangeValueForKey("myDate")
        myDate = NSDate()
        didChangeValueForKey("myDate")
    }
}

dynamic. "Swift Type 호환성"을 참조하십시오.

또한 동적 수식자를 사용하여 메서드의 구현을 동적으로 대체하는 키 값 관찰과 같은 API를 사용하는 경우 Objective-C 런타임에서 멤버에 대한 액세스를 동적으로 디스패치하도록 요구할 수 있습니다.

class MyObjectToObserve: NSObject {
    dynamic var myDate = NSDate()
    func updateDate() {
        myDate = NSDate()
    }
}

그리고 부동산 게터 및 세터 사용 시 호출됩니다.KVO를 사용할 때 확인할 수 있습니다.계산된 속성의 예입니다.

class MyObjectToObserve: NSObject {
    var backing: NSDate = NSDate()
    dynamic var myDate: NSDate {
        set {
            print("setter is called")
            backing = newValue
        }
        get {
            print("getter is called")
            return backing
        }
    }
}

현재 Swift는 '셀프' 이외의 오브젝트의 속성 변경을 감시하기 위한 빌트인 메커니즘을 지원하지 않으므로 KVO를 지원하지 않습니다.

그러나 KVO는 Objective-C와 Cocoa의 기본 요소이기 때문에 향후 추가될 가능성이 매우 높아 보입니다.현재 문서에는 다음과 같은 내용이 포함되어 있습니다.

주요 가치 관찰

정보가 곧 공개됩니다.

코코아 및 Objective-C와 함께 스위프트 사용

가지 중요한 은 Xcode를 7베타로 업데이트한 후 "Method does any method from the superclass"라는 메시지가 나타날 수 있습니다.그것은 그 주장의 선택권 때문이다.관찰 핸들러가 다음과 같이 표시되는지 확인합니다.

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [NSObject : AnyObject]?, context: UnsafeMutablePointer<Void>)

이것은 소수의 사람들에게 도움이 될 수 있다.

// MARK: - KVO

var observedPaths: [String] = []

func observeKVO(keyPath: String) {
    observedPaths.append(keyPath)
    addObserver(self, forKeyPath: keyPath, options: [.old, .new], context: nil)
}

func unObserveKVO(keyPath: String) {
    if let index = observedPaths.index(of: keyPath) {
        observedPaths.remove(at: index)
    }
    removeObserver(self, forKeyPath: keyPath)
}

func unObserveAllKVO() {
    for keyPath in observedPaths {
        removeObserver(self, forKeyPath: keyPath)
    }
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if let keyPath = keyPath {
        switch keyPath {
        case #keyPath(camera.iso):
            slider.value = camera.iso
        default:
            break
        }
    }
}

저는 Swift 3에서 이렇게 KVO를 사용했습니다.이 코드는 거의 변경하지 않고 사용할 수 있습니다.

개요

사용하지 않고 사용할 수 있습니다.NSObject ★★★★★★★★★★★★★★★★★」Objective-C

가용성:★★★★★★★★★★★★★★★★★★: iOS 13.0+,macOS 10.15+,tvOS 13.0+,watchOS 6.0+,Mac Catalyst 13.0+,Xcode 11.0+

참고: 값 유형이 없는 클래스에서만 사용해야 합니다.

코드:

Swift 버전: 5.1.2

import Combine //Combine Framework

//Needs to be a class doesn't work with struct and other value types
class Car {

    @Published var price : Int = 10
}

let car = Car()

//Option 1: Automatically Subscribes to the publisher

let cancellable1 = car.$price.sink {
    print("Option 1: value changed to \($0)")
}

//Option 2: Manually Subscribe to the publisher
//Using this option multiple subscribers can subscribe to the same publisher

let publisher = car.$price

let subscriber2 : Subscribers.Sink<Int, Never>

subscriber2 = Subscribers.Sink(receiveCompletion: { print("completion \($0)")}) {
    print("Option 2: value changed to \($0)")
}

publisher.subscribe(subscriber2)

//Assign a new value

car.price = 20

출력:

Option 1: value changed to 10
Option 2: value changed to 10
Option 1: value changed to 20
Option 2: value changed to 20

참조:

Int?와 CGFloat과 같은 유형의 문제에 부딪힌 사람을 위한 또 다른 예시는 무엇입니까?클래스를 NSObject의 하위 클래스로 설정하고 다음과 같이 변수를 선언하면 됩니다.

class Theme : NSObject{

   dynamic var min_images : Int = 0
   dynamic var moreTextSize : CGFloat = 0.0

   func myMethod(){
       self.setValue(value, forKey: "\(min_images)")
   }

}

언급URL : https://stackoverflow.com/questions/24092285/is-key-value-observation-kvo-available-in-swift

반응형