Swift selectors and number of arguments

In Swift, you can create and “perform” a #selector like below (e.g. in an iOS app) and it seems to work just fine (i.e. executes the “selected” function):

class Obj1 : NSObject {
    var value: String?
    @objc func setValue(value: String) -> Void {
        self.value = value
    }
    func run() -> Void {
        let selected = #selector(setValue(value:))
        perform(selected, with: "V")
        print(value!)
    }
}
Obj1().run() //outputs: "V"

Then you can add a new argument to the function definition like this, and running it through the selector would still work if you just add a second with argument to the perform call as well:

class Obj2 : NSObject {
    var value: String?
    @objc func setValue(value: String, suffix: String) -> Void {
        self.value = value + suffix
    }
    func run() -> Void {
        let selected = #selector(setValue(value:suffix:))
        perform(selected, with: "V", with "s")
        print(value!)
    }
}
Obj2().run() //outputs: "Vs"

But unfortunately you cannot follow the same pattern and add a third argument to setValue, expecting to be able to add another with – the code below doesn’t compile because there is no appropriate perform override available on NSObject – although the #selector expression itself would run correctly:

class Obj3 : NSObject {
    var value: String?
    @objc func setValue(
        prefix: String, value: String, suffix: String) -> Void {
            self.value = prefix + value + suffix
    }
    func run() -> Void {
        let selected = #selector(setValue(prefix:value:suffix:))
        perform(selected, with: "p", with: "V", with "s")
        print(value!)
    }
}
Obj3().run() //expected output: "pVs"; but Obj3 doesn't compile!

I assume this is mostly because such a construct would be rarely needed, so extending the library with more overrides would have just been too much overhead. Moreover, I understand that it is eventually possible to do it in a generic way by calling some lower level, Objective C library, functions. But I think it’s good to acknowledge this NSObject inheriting limitation (or should we call it inconsistence?) rather sooner than later.

Of course, if your selected function doesn’t have any argument, executing it with a selector would still work, just don’t pass any with argument to the perform call either. (Awkward conclusion: the approach works only with functions that have 0-2 arguments.)

Advertisements

About Sorin Dolha

My passion is software development, but I also like physics.
This entry was posted in iOS, macOS, Swift and tagged , , , , , . Bookmark the permalink.

Add a reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s