SwiftUI-KV观察并没有触发来自合并的完成

问题描述 投票:0回答:1

我正在尝试使用名为VOIP的lib来构建VailerSIPLib应用。由于库是使用Obj-C构建的,而大量使用NotificationCenter来发布更改,则活动状态遍布整个地方。

我目前在项目的CallView部分,我可以设法开始,结束,拒绝呼叫。但是,我需要在视图中实现connectionStatus,该视图将提供有关呼叫的信息,例如持续时间,“正在连接..”,“已断开连接”,“正在响铃”等。

下面的代码全部在CallViewModel: ObservableObject中;

变量:

var activeCall: VSLCall!
@Published var connectionStatus: String = ""

Initializer:

override init(){
        super.init()
        NotificationCenter.default.addObserver(self, selector: #selector(self.listen(_:)), name: Notification.Name.VSLCallStateChanged, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(self.buildCallView(_:)), name: Notification.Name.CallKitProviderDelegateInboundCallAccepted, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(self.buildCallView(_:)), name: Notification.Name.CallKitProviderDelegateOutboundCallStarted, object: nil)
    }

方法:

func setCall(_ call: VSLCall) {
    self.activeCall = call
    self.activeCall.observe(\.callStateText) { (asd, change) in
        print("observing")
        print("\(String(describing: change.oldValue)) to \(String(describing: change.newValue)) for \(call.callId)")
    } 
}

@objc func listen(_ notification: Notification) {
       if let _ = self.activeCall {
           print(self.activeCall.callStateText)
       }    
}

@objc func buildCallView(_ notification: Notification) {
    print("inbound call")
    self.isOnCall = true 
}

问题:

它打印出completionBlock中除setCall(_:)以外的所有内容。 listen(_:)函数可验证activeCall的状态是否正在更改,我想直接使用它,但是它并非始终都能正常工作。当使用callState.confirmed值应答呼叫时应触发该呼叫,但有时会触发。这将使我知道该开始计时了。

其他要点是,在VialerSIPLib的示例项目中,他们使用了self.activeCall.addObserver(_:),并且工作正常。问题在于它在类似didObservedValueChange(_:)的方法上引发运行时错误,并记录An -observeValueForKeyPath:ofObject:change:context: message was received but not handled.

最后在activeCall.observe(_:)处显示黄色警告

Result of call to 'observe(_:options:changeHandler:)' is unused我找不到与此相关的任何东西。

swift swiftui key-value-observing combine
1个回答
1
投票

最后在activeCall.observe(_ :)说黄色警告

Result of call to 'observe(_:options:changeHandler:)'

这是告诉您问题所在。 observe(_:options:changeHandler:)方法仅是incompletely documented。它返回类型为NSKeyValueObservation的对象,该对象表示您注册为键值观察器。您需要保存该对象,因为NSKeyValueObservation销毁后,它会取消注册。因此,您需要向CallViewModel添加属性以存储它:

class CallViewModel: ObservableObject {
    private var callStateTextObservation: NSKeyValueObservation?
    ...

然后您需要存储观察值:

func setCall(_ call: VSLCall) {
    activeCall = call
    callStateTextObservation = activeCall.observe(\.callStateText) { _, change in
        print("observing")
        print("\(String(describing: change.oldValue)) to \(String(describing: change.newValue)) for \(call.callId)")
    } 
}

您可以选择对KVO使用Combine API,尽管与Foundation API相比,它的文档更少。您得到一个Publisher,其输出是观察到的属性的每个新值。它是这样的:

class CallViewModel: ObservableObject {
    private var callStateTextTicket: AnyCancellable?
    ...

    func setCall(_ call: VSLCall) {
        activeCall = call
        callStateTextTicket = self.activeCall.publisher(for: \.callStateText, options: [])
            .sink { print("callId: \(call.callId), callStateText: \($0)") }
    }

没有示例理由在示例代码中使用Combine API,但通常PublisherNSKeyValueObservation更为灵活,因为Combine提供了许多对Publisher进行操作的方法。


您的addObserver(_:forKeyPath:options:context:)错误发生,因为这是一个较旧的API。早在发明Swift之前,它就已添加到NSObject中。实际上,它是在Objective-C甚至有块(关闭)之前添加的。使用该方法时,所有通知都将发送到观察者的observeValue(forKeyPath:of:change:context:)方法。如果您未实现observeValue方法,则NSObject中的默认实现会收到通知并引发异常。

© www.soinside.com 2019 - 2024. All rights reserved.