Search code examples
swiftobjective-cprotocolscombine

Swift property conforming to ObjC protocol has no member 'publisher'


In a larger ObjC/Swift-mixed codebase I have an ObjC protocol MyObjCProtocol <NSObject> that other ObjC classes need to conform to. It declares a string property @property (copy) NSString *myString.

Now, one of my Swift objects has a property conformsToObjCProtocol that is declared conforming to this protocol:

let conformsToObjCProtocol: MyObjCProtocol

This all works well. But when I try to observe myString using Combine like this:

let cancellable = conformsToObjCProtocol.publisher(for: \.myString).sink { print($0) }

I get an error Value of type 'any MyObjCProtocol' has no member 'publisher'.

I believe it should work because MyObjCProtocol is declared conforming to NSObject. I did add MyObjCProtocol.h to the bridging header too so that's not it. I can't rewrite the protocol in Swift because I need ObjC classes to conform to it. What can I do about this?


Solution

  • The Objective-C protocol is imported into Swift as a protocol that requires conformance to NSObjectProtocol. It does not require the conformer to inherit NSObject.

    If you declare the property like this:

    let conformsToObjCProtocol: MyObjCProtocol & NSObject
    

    then this can be observed using a NSObject.KeyValueObservingPublisher.

    NSObject.KeyValueObservingPublisher(
        object: conformsToObjCProtocol, keyPath: \.myString, options: []
    ).sink { ... }
    

    The publisher method unfortunately cannot be used here because of how it is declared. The declaration requires that you call it on a concrete type.