-
Notifications
You must be signed in to change notification settings - Fork 555
[UIKit] UIGestureRecognizer, support a way of unsubscribing without creating cycles #4729
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
d282075
f4a8e9b
57f0cac
2e28fa5
440c38a
5871aa8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,13 +12,17 @@ | |
|
|
||
| using System; | ||
| using System.Collections; | ||
| using System.Collections.Generic; | ||
| using Foundation; | ||
| using ObjCRuntime; | ||
| using CoreGraphics; | ||
|
|
||
| namespace UIKit { | ||
| public partial class UIGestureRecognizer { | ||
| object recognizers; | ||
| // | ||
| // Tracks the targets (NSObject, which we always enforce to be Token) to the Selector the point to, used when disposing | ||
| // | ||
| Dictionary<Token,IntPtr> recognizers = new Dictionary<Token,IntPtr> (); | ||
| const string tsel = "target"; | ||
| internal const string parametrized_selector = "target:"; | ||
| #if !XAMCORE_2_0 | ||
|
|
@@ -30,18 +34,26 @@ public partial class UIGestureRecognizer { | |
| { | ||
| } | ||
|
|
||
| // Called by the Dispose() method | ||
| void OnDispose () | ||
| { | ||
| foreach (var kv in recognizers) | ||
| RemoveTarget (kv.Key, kv.Value); | ||
| recognizers = null; | ||
| } | ||
|
|
||
| // | ||
| // Signature swapped, this is only used so we can store the "token" in recognizers | ||
| // | ||
| public UIGestureRecognizer (Selector sel, Token token) : this (token, sel) | ||
| { | ||
| recognizers = token; | ||
| recognizers [token] = sel.Handle; | ||
| MarkDirty (); | ||
| } | ||
|
|
||
| internal UIGestureRecognizer (IntPtr sel, Token token) : this (token, sel) | ||
| { | ||
| recognizers = token; | ||
| recognizers [token] = sel; | ||
| MarkDirty (); | ||
| } | ||
|
|
||
|
|
@@ -111,17 +123,7 @@ void RegisterTarget (Token target, IntPtr sel) | |
| { | ||
| AddTarget (target, sel); | ||
| MarkDirty (); | ||
| if (recognizers == null) | ||
| recognizers = target; | ||
| else { | ||
| Hashtable table = recognizers as Hashtable; | ||
| if (table == null){ | ||
| table = new Hashtable (); | ||
| table [recognizers] = recognizers; | ||
| recognizers = table; | ||
| } | ||
| table [target] = target; | ||
| } | ||
| recognizers [target] = sel; | ||
| } | ||
|
|
||
| public void RemoveTarget (Token token) | ||
|
|
@@ -130,12 +132,22 @@ public void RemoveTarget (Token token) | |
| throw new ArgumentNullException ("token"); | ||
| if (recognizers == null) | ||
| return; | ||
| if (recognizers == token) | ||
| recognizers = null; | ||
| Hashtable asHash = recognizers as Hashtable; | ||
| if (asHash != null) | ||
| asHash.Remove (token); | ||
| RemoveTarget (token, token is ParametrizedDispatch ? Selector.GetHandle (parametrized_selector) : Selector.GetHandle (tsel)); | ||
| if (recognizers.ContainsKey (token)){ | ||
|
||
| var sel = recognizers [token]; | ||
| recognizers.Remove (token); | ||
| RemoveTarget (token, sel); | ||
| } | ||
| } | ||
|
|
||
| // | ||
| // Used to enumerate all the registered handlers for this UIGestureRecognizer | ||
| // | ||
| public IEnumerable<Token> GetTargets () | ||
| { | ||
| if (recognizers == null) | ||
|
||
| yield break; | ||
| foreach (var kv in recognizers) | ||
| yield return kv.Key; | ||
| } | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that can cause an NRE here since the check (in
this) would be done later.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean because the selector might be null? I do not follow the "would be done later" part
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would call the constructor generated for the init: method, and that one should throw already if either sel or token are null in this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, the input can be
null, directly or indirectly, e.g.Selector.FromHandlecan returnnullnew UIGestureRecognizer (null, token);would throw theNullReferenceExceptionbefore it callsthis (token, sel)which has the null check (and would throw anArgumentNullException)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@spouliot the other (
this) constructor is called first, not last.