4

I am writing my iOS Application in Swift 3.

I have a UIViewController extension, where I have to check if the controller instance responds to a method. Below is the code that I a trying out.

extension UIViewController {
func myMethod() {
    if self.responds(to: #selector(someMethod)) {

    }
}}

Here the responds(to:) method throws a compile time error

Use of unresolved identifier "someMethod".

I read in another post, we have to use self inside the selector argument, but even that is throwing some error.

3
  • You need to implement func someMethod() {} which makes the method responds(to: useless Commented Oct 2, 2016 at 14:53
  • @vadian It is implemented in one of the View Controller instance.. But all the view controllers might not and that is what I intend to check. Commented Oct 2, 2016 at 14:59
  • I believe that you want to use a protocol with optional (or even non optional) methods, not just check random objects for a method. Commented Oct 2, 2016 at 15:08

3 Answers 3

5

A simple workaround:

@objc protocol SomeMethodType {
    func someMethod()
}
extension UIViewController {
    func myMethod() {
        if self.responds(to: #selector(SomeMethodType.someMethod)) {
            //...
            self.perform(#selector(SomeMethodType.someMethod))
            // or
            (self as AnyObject).someMethod?()
            //...
        }
    }
}

A little more Swifty way:

protocol SomeMethodType {
    func someMethod()
}
//For all classes implementing `someMethod()`.
extension MyViewController: SomeMethodType {}
//...
extension UIViewController {
    func myMethod() {
        if let someMethodSelf = self as? SomeMethodType {
            //...
            someMethodSelf.someMethod()
            //...
        }
    }
}
Sign up to request clarification or add additional context in comments.

4 Comments

Awesome! This seems to be the way to go. Thanks!
why do you have 2 extensions?
My interpretation: 1. Defines a new protocol. 2. Extends a specific subclass of UIViewController to be an implementor of that protocol. 3. Extends superclass to check whether any instance of itself (even if subclassed) implements the protocol, and if so, invokes the method required by the protocol, under the assumption that, if the protocol is defined, the method is present (because protocol requires it). Finally: The reason the second extension is there is it is not reasonable and almost certainly not possible to require every UIViewController to implement the protocol.
Obviously for this to work as shown the new protocol can't have any methods marked optional.
4

Create a protocol which requires someMethod()

protocol Respondable {
  func someMethod()
}

And a protocol extension which affects only UIViewController instances

extension Respondable where Self : UIViewController {

  func myMethod() {
    someMethod()
  }
}

Adopt the protocol to some of the view controllers

class VC1 : UIViewController, Respondable {
  func someMethod() { print("Hello") }
}

class VC2 : UIViewController {}
class VC3 : UIViewController {}

Now call the method in the extension

let vc1 = VC1()
vc1.myMethod() // "Hello"

Otherwise you get a compiler error:

let vc3 = VC3()
vc3.myMethod() // error: value of type 'VC3' has no member 'myMethod'

2 Comments

Thanks for the answer, but I am not sure if this method would suit my use case. I will get back once I confirm.
The benefit of the protocol solution is that the "check" is made at compile time.
0

Swift 4 answer:

If the selector is written as a string you won't get that error.

extension UIViewController {
    func myMethod() {
        if self.responds(to: "someMethod")) {

        }
    }
}

And then in the viewcontroller (dont forget the @objc):

@objc func someMethod() -> Void {}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.