Can Swift Method Defined on Extensions on Protocols Accessed in Objective-c

前端 未结 3 1758
走了就别回头了
走了就别回头了 2021-01-03 21:57

Is it possible to call methods defined in a protocol extension in Swift from Objective-C?

For example:

protocol Product {
    var price:Int { get }
          


        
相关标签:
3条回答
  • 2021-01-03 22:13

    I am nearly certain the answer to this is "no", although I haven't found official Apple documentation that spells it out.

    Here is a message from the swift-evolution mailing list discussing the proposal to use dynamic dispatch for all method calls, which would provide calling semantics more like Objective-C:

    Again, the sole exception to this is protocol extensions. Unlike any other construct in the language, protocol extension methods are dispatched statically in a situation where a virtual dispatch would cause different results. No compiler error prevents this mismatch. (https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001707.html)

    Protocol extensions are a Swift-only language feature, and as such are not visible to objc_msgSend().

    0 讨论(0)
  • 2021-01-03 22:14

    If it is ok to remove the priceString from the protocol, and only have it in your extension, you can call the protocol extension by casting IceCream to a Product in a helper extension.

    @objc protocol Product {
        var price:Int { get }
    }
    
    extension Product {
        var priceString:String {
            return "$\(price)"
        }
    }
    
    // This is the trick
    // Helper extension to be able to call protocol extension from obj-c
    extension IceCream : Product {
        var priceString:String {
            return (self as Product).priceString
        }
    }
    
    @objc class IceCream: NSObject {
        var price: Int {
            return 2
        }
    }
    
    0 讨论(0)
  • 2021-01-03 22:32

    Protocol extension does not work with @objc protocol, however you can extend the class in swift as a workaround.

    @objc protocol Product {
       var price: NSNumber? { get }
       var priceString:String { get }
    }
    
    ...
    // IceCream defined in Objective-C that does not extend Product
    // but has @property(nonatomic, strong, nullable) (NSNumber*)price
    // to make it confirm to Product
    ...
    extension IceCream: Product {
       var priceString:String {
          get {
            return "$\(price ?? "")"
          }
       }
    }
    

    This code is not clean at all, but it works.

    0 讨论(0)
提交回复
热议问题