在更大的 ObjC/Swift 混合代码库中,我有一个 ObjC 协议
MyObjCProtocol <NSObject>
,其他 ObjC 类需要遵守。它声明了一个字符串属性@property (copy) NSString *myString
。
现在,我的一个 Swift 对象有一个属性
conformsToObjCProtocol
声明符合此协议:
let conformsToObjCProtocol: MyObjCProtocol
这一切都运作良好。 但是当我尝试像这样使用组合来观察
myString
时:
let cancellable = conformsToObjCProtocol.publisher(for: \.myString).sink { print($0) }
我收到错误
Value of type 'any MyObjCProtocol' has no member 'publisher'
。
我相信它应该可以工作,因为 MyObjCProtocol 被声明为符合 NSObject。我也将 MyObjCProtocol.h 添加到桥接标头中,所以不是这样。我无法在 Swift 中重写协议,因为我需要 ObjC 类来遵守它。对此我能做什么?
您面临的问题是由于即使您的协议
MyObjCProtocol
继承自 NSObject
,Combine 也不会自动识别发布属性。 publisher(for:)
方法是Combine为支持键值观察(KVO)的对象提供的扩展,它并不直接应用于Objective-C中的协议。
这里有一个 Swift 解决方案来解决这个问题:
为 NSObject 创建扩展:您可以为
NSObject
创建扩展,为 KVO 兼容属性提供发布者方法。
使用AnyObject代替MyObjCProtocol:由于Combine需要具体的引用,而你的协议只是一个抽象,所以你需要使用
AnyObject
并确保你的具体对象符合协议。
以下是如何执行此操作的示例:
import Combine
import Foundation
extension NSObject {
func publisher<T>(for keyPath: KeyPath<NSObject, T>) -> AnyPublisher<T, Never> {
Publishers.KVObservablePublisher(object: self, keyPath: keyPath)
.eraseToAnyPublisher()
}
}
import Combine
// Ensure your concrete object is an NSObject and conforms to the protocol
let objcObject: AnyObject = conformsToObjCProtocol as AnyObject
// Force cast objcObject to NSObject to use the extension
guard let nsObject = objcObject as? NSObject else {
fatalError("The object is not an NSObject")
}
// Create the publisher and subscribe to it
let cancellable = nsObject.publisher(for: \.myString).sink { newValue in
print(newValue)
}
确保
myString
在您的 Objective-C 类中正确暴露给 KVO。这应该可以解决问题并允许您使用组合观察属性的变化。