Notice (2018-05-24): bugzilla.xamarin.com is now in
Please join us on
Visual Studio Developer Community and in the
Mono organizations on
GitHub to continue tracking issues. Bugzilla will remain
available for reference in read-only mode. We will continue to work
on open Bugzilla bugs, copy them to the new locations
as needed for follow-up, and add the new items under Related
Our sincere thanks to everyone who has contributed on this bug
tracker over the years. Thanks also for your understanding as we
make these adjustments and improvements for the future.
Please create a new report on
Developer Community or GitHub with
your current version information, steps to reproduce, and relevant error
messages or log files if you are hitting an issue that looks similar to
this resolved bug and you do not yet see a matching new report.
The binding for NSObject.PerformSelector(selector, data, delay) is incorrectly using a float value for delay rather than a double. This could potentially affect other bindings to methods / properties that use NSTimeInterval, which is a double. Have not done a pass through the Mono APIs to check for this.
IT SEEMS THAT THE SAME BUG MAY BE PRESENT FOR MonoTouch AS WELL -- have not verified this, though - but the same P/Invoke calls are made, it seems.
Initially noticed this after upgrading to MonoDevelop 126.96.36.199 -- unsure if this was due to the update, or if "something" changed and a latent problem was exposed -- our code had not changed when this bug was detected.
The changed behavior was that some (but not all) selectors were not called at all -- nor were custom data objects passed to the uncalled selectors ever GC'd. I suspect that four of the bytes in the expected double precision 'delay' value were garbage, and happened to result in extremely large values for 'delay'. Also observed that when requesting a long delay, e.g. 10 seconds, selectors that were called were definitely *not* called after 10 sec -- usually they fired right away, or not at all.
After making the change described below, selectors seem to be called after the expected delay, and are not missed.
Docs for performSelector:withObject:afterDelay -->
As a workaround, you can do the following...
A) Use BeginInvokeOnUIThread() instead if 'delay' is not necessary, and it's OK to execute selector on UI thread
B) Patch PerformSelector():
1) Add necessary P/Invoke calls to pass delay as a double (aren't in the Messaging class)
2) For classes you're interested in using NSObject.PerformSelector, override PerformSelector and call the new entry points.
// Add P/Invoke for objc_msgSend / objc_msgSendSuper that accept double arg
internal static class MyMessaging
[DllImport("/usr/lib/libobjc.dylib", EntryPoint = "objc_msgSend")]
public static extern void void_objc_msgSend_intptr_intptr_Double(IntPtr receiver, IntPtr selector, IntPtr arg1, IntPtr arg2, double arg3);
[DllImport("/usr/lib/libobjc.dylib", EntryPoint = "objc_msgSendSuper")]
public static extern void void_objc_msgSendSuper_intptr_intptr_Double(IntPtr receiver, IntPtr selector, IntPtr arg1, IntPtr arg2, double arg3);
// Patch PerformSelector
public partial MyClass
private static IntPtr selPerformSelectorWithObjectAfterDelay = MonoMac.ObjCRuntime.Selector.GetHandle ("performSelector:withObject:afterDelay:");
public override void PerformSelector (MonoMac.ObjCRuntime.Selector sel, NSObject obj, float delay)
MyMessaging.void_objc_msgSend_intptr_intptr_Double(this.Handle, selPerformSelectorWithObjectAfterDelay, sel.Handle, (obj != null) ? obj.Handle : IntPtr.Zero, delay);
MyMessaging.void_objc_msgSendSuper_intptr_intptr_Double(this.SuperHandle, selPerformSelectorWithObjectAfterDelay, sel.Handle, (obj != null) ? obj.Handle : IntPtr.Zero, delay);
I just fixed that in monomac commit 7d9f63. Long delays are working fine after doing the float->double change, I tested several times with 0, 1, 3, 5, 10, 15 and 45 seconds.
Monotouch is not done yet, but I'll ask someone from the monotouch team to have a look at it.
This was a typo in MonoMac, MonoTouch did not have that problem.