[swift-users] Calling default implementation of protocol methods as selectors

Zhao Xin owenzx at gmail.com
Sun Jun 4 06:55:09 CDT 2017


Will this work?

class TapGestureRecognizer: UITapGestureRecognizer {

    var onTap: (() -> Void)?

    init(onTap: (() -> Void)?) {

        self.onTap = onTap

        super.init(target: nil, action: nil)

*        self.removeTarget(nil, action: nil)*

        self.addTarget(self, action: #selector(internalTapHandler))

        print(self)

    }



    @objc private func internalTapHandler() {

        onTap?()

    }

}

Zhao Xin

On Sun, Jun 4, 2017 at 5:24 PM, Nate Birkholz <nbirkholz at gmail.com> wrote:

> Also, note that I tried the following:
>
> class BlockTapGestureRecognizer: UIGestureRecognizer {
>     var onTap: (() -> Void)?
>     init(onTap: (() -> Void)?) {
>         self.onTap = onTap
>         super.init(target: nil, action: nil)
>         self.addTarget(self, action: #selector(internalTapHandler))
>         print(self)
>     }
>
>     @objc private func internalTapHandler() {
>         onTap?()
>     }
> }
>
> And the object prints looking okay:
>
> <Artmospherez.BlockTapGestureRecognizer: 0x1701998b0; baseClass =
> UIGestureRecognizer; state = Possible; view = <UIView 0x100c60870>; target=
> <(action=internalTapHandler, target=<Artmospherez.BlockTapGestureRecognizer
> 0x1701998b0>)>>
>
> But it doesn't in practice work. The documentation for the (target:
> action:) initializer states:
>
> target: An object that is the recipient of action messages sent by the
> receiver when it recognizes a gesture. nil is not a valid value.
> action: A selector that identifies the method implemented by the target to
> handle the gesture recognized by the receiver. The action selector must
> conform to the signature described in the class overview. NULL is not a
> valid value.
>
> So something is going on inside there when the nil values are passed to
> the recognizer. As the documentation states, nil is not a valid value and
> it must cause troubles.
>
> Or I did something wrong?
>
>
>
> On Sun, Jun 4, 2017 at 1:55 AM, Nate Birkholz <nbirkholz at gmail.com> wrote:
>
>> Ah, I didn't read the rest of the thread. As Zhao Xin notes, you cannot
>> call super.init(target: self, action: #selector()), and you cannot call
>> super.init() in a subclass init or convenience init, it *has* to be the
>> designated init method init(target:action:). That's too bad, closure-based
>> gesture recognizers would be snazzy and swifty and I'd love to see them as
>> part of UIKit.
>>
>> I could write my own custom implementations of subclassed
>> UIKit.UIGestureRecognizerSubclass(es), but as the screens in question
>> have tap, swipe up, swipe down, and swipe right gesture recognizers, I feel
>> its overkill to write all that to avoid repeating ~10 lines of code.
>>
>> On Sun, Jun 4, 2017 at 1:21 AM, Nate Birkholz <nbirkholz at gmail.com>
>> wrote:
>>
>>> I briefly considered something like this but didn't explore it. Elegant.
>>>
>>> Sent from my iPhone, please excuse brevity and errors
>>>
>>> On Jun 3, 2017, at 9:38 PM, Geordie Jay <geojay at gmail.com> wrote:
>>>
>>> I am dealing with a variant of this on Android right now. I have just
>>> subclassed e.g. UITapGestureRecognizer to perform the 2nd variant above and
>>> externally accept a closure as its argument. I'm writing this on my phone
>>> so forgive any syntax errors or accidental omissions:
>>>
>>> class TapGestureRecognizer: UITapGestureRecognizer {
>>> var onTap: (() -> Void)?
>>> init(onTap: (() -> Void)?) {
>>> self.onTap = onTap
>>> super.init(target: self, action: #selector(internalTapHandler))
>>> }
>>>
>>> @objc private func internalTapHandler() {
>>> onTap?()
>>> }
>>> }
>>>
>>> class Baz: Foo {
>>> init() {
>>> let tapRecognizer = TapGestureRecognizer(onTap: self.bar)
>>> }
>>> }
>>>
>>>
>>> Cheers,
>>> Geordie
>>> On Sat 3. Jun 2017 at 16:53, Nate Birkholz via swift-users <
>>> swift-users at swift.org> wrote:
>>>
>>>> Thanks, the second had occurred to me, but felt a little too much like
>>>> in practice it would make the code harder to understand.
>>>>
>>>> On Fri, Jun 2, 2017 at 9:58 PM, Zhao Xin <owenzx at gmail.com> wrote:
>>>>
>>>>> I found two workarounds.
>>>>>
>>>>> 1.
>>>>>
>>>>> protocol Foo: class {
>>>>>
>>>>>     func bar()
>>>>>
>>>>> }
>>>>>
>>>>>
>>>>> class Base:Foo {
>>>>>
>>>>>     @objc func bar() {
>>>>>
>>>>>         print("bar")
>>>>>
>>>>>     }
>>>>>
>>>>> }
>>>>>
>>>>>
>>>>> class Baz: Base {
>>>>>
>>>>>     override init() {
>>>>>
>>>>>         super.init()
>>>>>
>>>>>         let tapRecognizer = UITapGestureRecognizer(target: self,
>>>>> action: #selector(bar))
>>>>>
>>>>>     }
>>>>>
>>>>> }
>>>>>
>>>>> 2.
>>>>>
>>>>> protocol Foo: class {
>>>>>
>>>>>     func bar()
>>>>>
>>>>> }
>>>>>
>>>>>
>>>>> extension Foo {
>>>>>
>>>>>     func bar() {
>>>>>
>>>>>         print("bar")
>>>>>
>>>>>     }
>>>>>
>>>>> }
>>>>>
>>>>>
>>>>> class Baz: Foo {
>>>>>
>>>>>     init() {
>>>>>
>>>>>         let tapRecognizer = UITapGestureRecognizer(target: self,
>>>>> action: #selector(delegate))
>>>>>
>>>>>     }
>>>>>
>>>>>
>>>>>
>>>>>     @objc func delegate() {
>>>>>
>>>>>         bar()
>>>>>
>>>>>     }
>>>>>
>>>>> }
>>>>>
>>>>>
>>>>> Zhao Xin
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> On Sat, Jun 3, 2017 at 10:35 AM, Nate Birkholz via swift-users <
>>>>> swift-users at swift.org> wrote:
>>>>>
>>>>>> protocol Foo: class {
>>>>>>     func bar()
>>>>>> }
>>>>>>
>>>>>> extension Foo {
>>>>>>     func bar() {
>>>>>>          print("bar")
>>>>>>     }
>>>>>> }
>>>>>>
>>>>>> class Baz: Foo {
>>>>>>     init() {
>>>>>>         let tapRecognizer = UITapGestureRecognizer(target: self,
>>>>>> action: #selector(bar))
>>>>>>     }
>>>>>> }
>>>>>>
>>>>>> the #selector tells me: "Argument of '#selector' refers to instance
>>>>>> method 'bar()' that is not exposed to Objective-C" and asks me to add @objc
>>>>>> to the method definition.
>>>>>>
>>>>>> Adding @objc to the method tells me: "@objc can only be used with
>>>>>> members of classes, @objc protocols, and concrete extensions of classes"
>>>>>>
>>>>>> Adding @objc to the protocol doesn't fix it, just introduces new
>>>>>> issues.
>>>>>>
>>>>>> "dynamic" cannot be applied to a protocol, so cannot be used
>>>>>> alternatively.
>>>>>>
>>>>>> Is there a way to get around this? If a method is called by a gesture
>>>>>> recognizer, is there no way to have a default protocol implementation? I'd
>>>>>> like to use default implementations if possible to make my code more DRY.
>>>>>>
>>>>>> Is there a roadmap/plan for swift-native selector dispatch?
>>>>>>
>>>>>> Thanks. I look forward to the inevitable reply revealing the dumb
>>>>>> thing I missed. :)
>>>>>>
>>>>>> --
>>>>>> Nate Birkholz
>>>>>>
>>>>>> _______________________________________________
>>>>>> swift-users mailing list
>>>>>> swift-users at swift.org
>>>>>> https://lists.swift.org/mailman/listinfo/swift-users
>>>>>>
>>>>>>
>>>>>
>>>>
>>>>
>>>> --
>>>> Nate Birkholz
>>>> _______________________________________________
>>>> swift-users mailing list
>>>> swift-users at swift.org
>>>> https://lists.swift.org/mailman/listinfo/swift-users
>>>>
>>>
>>
>>
>> --
>> Nate Birkholz
>>
>
>
>
> --
> Nate Birkholz
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20170604/e091884a/attachment.html>


More information about the swift-users mailing list