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 <geo...@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 <owe...@gmail.com >> <mailto: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