[swift-users] Calling default implementation of protocol methods as selectors
Nate Birkholz
nbirkholz at gmail.com
Sun Jun 4 11:08:01 CDT 2017
Technically it does work(!), but I am hesitant to use it in what amounts to
sample code for my current job search, haha.
On Sun, Jun 4, 2017 at 4:55 AM, Zhao Xin <owenzx at gmail.com> wrote:
> 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
>>
>
>
--
Nate Birkholz
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20170604/8f8356ef/attachment.html>
More information about the swift-users
mailing list