Calling default implementation of protocol methods as selectors

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

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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

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@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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
Nate Birkholz

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@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@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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
Nate Birkholz
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

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@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@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@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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
Nate Birkholz
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

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@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@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@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@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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
Nate Birkholz
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
Nate Birkholz

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@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@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@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@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@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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
Nate Birkholz
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
Nate Birkholz

--
Nate Birkholz

You should change to another way. Using `self` in `super.init` is not
allowed.

Zhaoxin

···

On Sun, Jun 4, 2017 at 12:38 PM, Geordie Jay <geojay@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@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@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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
Nate Birkholz
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

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@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@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@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@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@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@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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
Nate Birkholz
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
Nate Birkholz

--
Nate Birkholz

Thanks for the amendment, and sorry for the (lack of) formatting. I
painstakingly typed that on my phone with manually-spaced indenting, which
the Inbox app unhelpfully removed entirely when I pressed send. Pasting
into Xcode should do the trick though..

Geordie

···

On Sun 4. Jun 2017 at 14:49, Zhao Xin <owenzx@gmail.com> wrote:

You should change to another way. Using `self` in `super.init` is not
allowed.

Zhaoxin

On Sun, Jun 4, 2017 at 12:38 PM, Geordie Jay <geojay@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@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@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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
Nate Birkholz
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

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@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@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@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@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@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@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@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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
Nate Birkholz
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
Nate Birkholz

--
Nate Birkholz

--
Nate Birkholz

Here’s what I’d try.

(disclaimer: written in Mail, may contain errors, yadda yadda yadda)

public class BlockTapGestureRecognizer: UITapGestureRecognizer {
    private class Target: NSObject {
        private let closure: (UITapGestureRecognizer) -> ()
        
        init(closure: @escaping (UITapGestureRecognizer) -> ()) {
            self.closure = closure
            super.init()
        }
        
        @objc func performClosure(_ sender: Any?) {
            guard let recognizer = sender as? UITapGestureRecognizer else {
                print("Unexpected sender (expected UITapGestureRecognizer)")
                return
            }
            
            self.closure(recognizer)
        }
    }
    
    private let target: Target
    
    public init(closure: @escaping (UITapGestureRecognizer) -> ()) {
        self.target = Target(closure: closure)
        super.init(target: self.target, action: selector(Target.performClosure(_:)))
    }
}

No need for weird hacks passing nil as the target or action.

Charles

···

On Jun 4, 2017, at 11:08 AM, Nate Birkholz via swift-users <swift-users@swift.org> wrote:

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@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@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@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@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@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@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@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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
Nate Birkholz
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
Nate Birkholz

--
Nate Birkholz

--
Nate Birkholz
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

I was not talking about the formatting. I am talking about the
implementation.

You can't use `self` before you call `super.init` as you did now. If
changing your implementation to called `super.init` and then call `self`
in `super.init` again. You would have called `super.init` twice. I don't
know what that means. But it smells bad.

Zhaoxin

···

On Sun, Jun 4, 2017 at 12:51 PM, Geordie Jay <geojay@gmail.com> wrote:

Thanks for the amendment, and sorry for the (lack of) formatting. I
painstakingly typed that on my phone with manually-spaced indenting, which
the Inbox app unhelpfully removed entirely when I pressed send. Pasting
into Xcode should do the trick though..

Geordie

On Sun 4. Jun 2017 at 14:49, Zhao Xin <owenzx@gmail.com> wrote:

You should change to another way. Using `self` in `super.init` is not
allowed.

Zhaoxin

On Sun, Jun 4, 2017 at 12:38 PM, Geordie Jay <geojay@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@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@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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
Nate Birkholz
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

To get around the issue of using self on init, but also that of multiple recogniser types, try this:

class ClosureGestureRecognizer<RecognizerType: UIGestureRecognizer> {
    // These are initially nil and set on init to their desired values.
    // This gets around the issue of using self in init.
    // `private` means they can't ever actually be nil:
    private var recognizer: RecognizerType!
    private var onAction: ((RecognizerType) -> Void)!

    init(callback: @escaping ((RecognizerType) -> Void)) {
        recognizer = RecognizerType(target: self, action: selector(actionHandler))
        self.onAction = callback
    }

    @objc private func actionHandler() {
        onAction(recognizer)
    }
}

let recognizer = ClosureGestureRecognizer<UIPanGestureRecognizer>(callback: { panGestureRecognizer in
    print("Panned, translation:", panGestureRecognizer.translation(in: nil))
})

Regards,
Geordie

···

Am 04.06.2017 um 21:55 schrieb Zhao Xin <owenzx@gmail.com>:

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@gmail.com <mailto:nbirkholz@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@gmail.com <mailto:nbirkholz@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@gmail.com <mailto:nbirkholz@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@gmail.com <mailto:geojay@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@swift.org <mailto:swift-users@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@gmail.com <mailto:owenzx@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@swift.org <mailto:swift-users@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@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

--
Nate Birkholz
_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

--
Nate Birkholz

--
Nate Birkholz

That's why I thanked for for the amendment. As I said, typing code blindly
on the phone, mistakes are inevitable. Thanks for clearing it up.

···

On Sun 4. Jun 2017 at 15:04, Zhao Xin <owenzx@gmail.com> wrote:

I was not talking about the formatting. I am talking about the
implementation.

You can't use `self` before you call `super.init` as you did now. If
changing your implementation to called `super.init` and then call `self`
in `super.init` again. You would have called `super.init` twice. I don't
know what that means. But it smells bad.

Zhaoxin

On Sun, Jun 4, 2017 at 12:51 PM, Geordie Jay <geojay@gmail.com> wrote:

Thanks for the amendment, and sorry for the (lack of) formatting. I
painstakingly typed that on my phone with manually-spaced indenting, which
the Inbox app unhelpfully removed entirely when I pressed send. Pasting
into Xcode should do the trick though..

Geordie

On Sun 4. Jun 2017 at 14:49, Zhao Xin <owenzx@gmail.com> wrote:

You should change to another way. Using `self` in `super.init` is not
allowed.

Zhaoxin

On Sun, Jun 4, 2017 at 12:38 PM, Geordie Jay <geojay@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@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@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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
Nate Birkholz
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

In fact, this would be even better (avoids unnecessary implicitly unwrapped optionals):

class ClosureGestureRecognizer<GestureRecognizer: UIGestureRecognizer> {
    fileprivate var recognizer: GestureRecognizer
    private var onAction: ((GestureRecognizer) -> Void)

    init(onAction: @escaping ((GestureRecognizer) -> Void)) {
        self.recognizer = GestureRecognizer()
        self.onAction = onAction

        self.recognizer.addTarget(self, action: selector(actionHandler))
    }

    @objc private func actionHandler() {
        onAction(recognizer)
    }
}

extension UIView {
    func addGestureRecognizer<T>(_ gestureRecognizer: ClosureGestureRecognizer<T>) {
        self.addGestureRecognizer(gestureRecognizer.recognizer)
    }
}

Depending on your use-case, it’d be no problem to make onAction a non-private (externally settable) optional closure—in case you want to avoid having to set it on init of ClosureGestureRecognizer.

Cheers,
Geordie

···

Am 04.06.2017 um 23:09 schrieb Geordie J <geojay@gmail.com>:

To get around the issue of using self on init, but also that of multiple recogniser types, try this:

class ClosureGestureRecognizer<RecognizerType: UIGestureRecognizer> {
    // These are initially nil and set on init to their desired values.
    // This gets around the issue of using self in init.
    // `private` means they can't ever actually be nil:
    private var recognizer: RecognizerType!
    private var onAction: ((RecognizerType) -> Void)!

    init(callback: @escaping ((RecognizerType) -> Void)) {
        recognizer = RecognizerType(target: self, action: selector(actionHandler))
        self.onAction = callback
    }

    @objc private func actionHandler() {
        onAction(recognizer)
    }
}

let recognizer = ClosureGestureRecognizer<UIPanGestureRecognizer>(callback: { panGestureRecognizer in
    print("Panned, translation:", panGestureRecognizer.translation(in: nil))
})

Regards,
Geordie

Am 04.06.2017 um 21:55 schrieb Zhao Xin <owenzx@gmail.com <mailto:owenzx@gmail.com>>:

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@gmail.com <mailto:nbirkholz@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@gmail.com <mailto:nbirkholz@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@gmail.com <mailto:nbirkholz@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@gmail.com <mailto:geojay@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@swift.org <mailto:swift-users@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@gmail.com <mailto:owenzx@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@swift.org <mailto:swift-users@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@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

--
Nate Birkholz
_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

--
Nate Birkholz

--
Nate Birkholz

That works great and is very elegant. Nice work.

···

On Sun, Jun 4, 2017 at 6:34 AM, Geordie J <geojay@gmail.com> wrote:

In fact, this would be even better (avoids unnecessary implicitly
unwrapped optionals):

class ClosureGestureRecognizer<GestureRecognizer: UIGestureRecognizer> {
    fileprivate var recognizer: GestureRecognizer
    private var onAction: ((GestureRecognizer) -> Void)

    init(onAction: @escaping ((GestureRecognizer) -> Void)) {
        self.recognizer = GestureRecognizer()
        self.onAction = onAction

        self.recognizer.addTarget(self, action: selector(actionHandler))
    }

    @objc private func actionHandler() {
        onAction(recognizer)
    }
}

extension UIView {
    func addGestureRecognizer<T>(_ gestureRecognizer:
ClosureGestureRecognizer<T>) {
        self.addGestureRecognizer(gestureRecognizer.recognizer)
    }
}

Depending on your use-case, it’d be no problem to make *onAction* a
non-private (externally settable) optional closure—in case you want to
avoid having to set it on init of ClosureGestureRecognizer.

Cheers,
Geordie

Am 04.06.2017 um 23:09 schrieb Geordie J <geojay@gmail.com>:

To get around the issue of using self on init, but also that of multiple
recogniser types, try this:

class ClosureGestureRecognizer<RecognizerType: UIGestureRecognizer> {
    // These are initially nil and set on init to their desired values.
    // This gets around the issue of using self in init.
    // `private` means they can't ever actually be nil:
    private var recognizer: RecognizerType!
    private var onAction: ((RecognizerType) -> Void)!

    init(callback: @escaping ((RecognizerType) -> Void)) {
        recognizer = RecognizerType(target: self, action: selector(
actionHandler))
        self.onAction = callback
    }

    @objc private func actionHandler() {
        onAction(recognizer)
    }
}

let recognizer = ClosureGestureRecognizer<UIPanGestureRecognizer>(callback:
{ panGestureRecognizer in
    print("Panned, translation:", panGestureRecognizer.translation(in: nil
))
})

Regards,
Geordie

Am 04.06.2017 um 21:55 schrieb Zhao Xin <owenzx@gmail.com>:

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@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@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@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@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@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@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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
Nate Birkholz
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

--
Nate Birkholz

--
Nate Birkholz

--
Nate Birkholz

Hello, I'm finding this thread a few years later and would love to use @ephemer 's solution in one of my project.

I've tested this with a basic implementation but for some reason whenever I add a GestureRecognizer to one of my views, the target always remains "null" and as a result, the gesture isn't being recognized.

My test implementation:

class TestVC: UIViewController {`    
    var label: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        label = UILabel()
        label.text = "Text"
        label.translatesAutoresizingMaskIntoConstraints = false
        label.isUserInteractionEnabled = true
        
        view.addSubview(label)
        label.centerInSuperview(size: CGSize(width: 100, height: 100))
        
        let tapGesture = ClosureGestureRecognizer<UITapGestureRecognizer> { (tap) in
            print("Tapped")
        }
            
        label.addGestureRecognizer(tapGesture)

   }
}

Debug output

(lldb) e UIView $view = (UIView) 0x104b21300**
(lldb) po [$view gestureRecognizers]
<__NSSingleObjectArrayI 0x280ac9c00>(
<UITapGestureRecognizer: 0x104b25c10; state = Possible; view = <UILabel 0x104b21300>; target= <(action=actionHandler, target=<(null) 0x0>)>>
)

Any thoughts on what I'm missing to make this work? I tried to add the label in viewDidAppear just in case but no luck.

My ultimate goal is to create a Transformable protocol to add the ability to transform (pan, pinch & rotate) many classes I have in this project.

Thanks in advance.

Your gesture lost its reference. Try this

var label: UILabel!

var tapGesture:ClosureGestureRecognizer!

in viewDidLoad()

tapGesture = ClosureGestureRecognizer { (tap) in
print("Tapped")
}

Thank you so much. That did the trick.