我正在尝试使用名为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
我找不到与此相关的任何东西。
最后在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,但通常Publisher
比NSKeyValueObservation
更为灵活,因为Combine提供了许多对Publisher
进行操作的方法。
您的addObserver(_:forKeyPath:options:context:)
错误发生,因为这是一个较旧的API。早在发明Swift之前,它就已添加到NSObject
中。实际上,它是在Objective-C甚至有块(关闭)之前添加的。使用该方法时,所有通知都将发送到观察者的observeValue(forKeyPath:of:change:context:)
方法。如果您未实现observeValue
方法,则NSObject
中的默认实现会收到通知并引发异常。