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 <owe...@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 <nbirkh...@gmail.com > <mailto:nbirkh...@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 <nbirkh...@gmail.com > <mailto:nbirkh...@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 <nbirkh...@gmail.com > <mailto:nbirkh...@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 <geo...@gmail.com > <mailto:geo...@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 <owe...@gmail.com >> <mailto:owe...@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 >> <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 >> <https://lists.swift.org/mailman/listinfo/swift-users> > > > > -- > Nate Birkholz > > > > -- > Nate Birkholz >
_______________________________________________ swift-users mailing list swift-users@swift.org https://lists.swift.org/mailman/listinfo/swift-users