2

I simulate my case in this example:

protocol MyProtocol {

    func doSomething()
}

extension MyProtocol {

    func doSomething() {
        print("Do something")
    }
}

class MyViewController: UIViewController, MyProtocol {

    let button = UIButton()

    override func viewDidLoad() {
        super.viewDidLoad()
        button.addTarget(self, action: #selector(doSomething), for: .touchUpInside)
    }
}

I was expecting that MyViewController has already implemented doSomething() function, cause it was implemented in MyProtocol extension. Unfortunately I'm getting this error:

error: argument of '#selector' refers to instance method 'doSomething()' that is not exposed to Objective-C

Am I able to fix or workaround this?

Nominalista
  • 4,632
  • 11
  • 43
  • 102
  • Please refer this one http://stackoverflow.com/questions/40501780/examples-of-delegates-in-swift-3 – Bhupat Bheda Apr 28 '17 at 10:59
  • How it's related to question? – Nominalista Apr 28 '17 at 11:01
  • According to http://stackoverflow.com/questions/39487168/non-objc-method-does-not-satisfy-optional-requirement-of-objc-protocol (possible duplicate?) you cannot define Objective-C compatible methods in protocol extensions. – Martin R Apr 28 '17 at 11:08

2 Answers2

0

Your protocol is not Objective-C compatible. You need to annotate it with @objc or you won't be able to use the selector because the methods won't use Objective-C dispatch.

EDIT

So I should have tried it in a playground before writing the above.

You can't add an @objc function to a protocol extension in Swift. You'll have to put it in the class. or you can extend UIViewController to implement MyProtocol

e.g.

@objc protocol MyProtocol 
{
    @objc func doSomething();
} 

extension UIViewController: MyProtocol
{
    @objc func doSomething() { /* implementation */ }   
}
JeremyP
  • 84,577
  • 15
  • 123
  • 161
  • 1
    Did you try that? I wasn't able to make it compile, and according to http://stackoverflow.com/questions/39487168/non-objc-method-does-not-satisfy-optional-requirement-of-objc-protocol it might be not possible. Seems like a duplicate to me. – Martin R Apr 28 '17 at 11:09
  • @MartinR I've tried it now, and it's illegal to put an obj-c method in a protocol extension. The error message specifically says so. – JeremyP Apr 28 '17 at 11:13
0

I run into the same problem and solved it with a wrap object.

protocol MyProtocol: class {

    func doSomething()
}

extension MyProtocol {

    func doSomething() {
        print("Do something")
    }
}

final class ObjCMyProtocolWrap: NSObject, MyProtocol {

    // MARK: - init

    override init() {
        fatalError("Not supported!")
    }

    init(_ origin: MyProtocol) {
        self.origin = origin
    }

    // MARK: - protocol: Executable

    func doSomething() {
        origin.doSomething()
    }

    // MARK: - private

    private let origin: MyProtocol

}

Now you can use it like that:

let action: MyProtocol = OriginalObject()
let objcAction: MyProtocol = ObjCMyProtocolWrap(action)
button.addTarget(objcAction, action: #selector(ObjCMyProtocolWrap.doSomething), for: .touchUpInside)

But note: You have to store a reference to the wrap object (objcAction in this example)! The UIButton holds a weak reference only!

ObjectAlchemist
  • 1,109
  • 1
  • 9
  • 18