Skip to content

Commit 096ce80

Browse files
Made accesses to ApplicationIconBadgeNumber always use the main queue.
In Xamarin.iOS, any accessess made to a UIKit property that's labeled as `nonatomic` on a thread other than the main thread results in an exception being thrown. This was causing installation saves to fail quietly (very bad). We solve this problem by forcing usage of these properties onto the main queue, and although this provides an avenue for deadlock, it's better than simply having silent failures in most cases.
1 parent 02903d0 commit 096ce80

File tree

1 file changed

+27
-3
lines changed

1 file changed

+27
-3
lines changed

Parse/ParseInstallation.iOS.cs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using Foundation;
1111
using UIKit;
1212
using System.Threading.Tasks;
13+
using CoreFoundation;
1314

1415
namespace Parse {
1516
public partial class ParseInstallation : ParseObject {
@@ -54,16 +55,39 @@ public void SetDeviceTokenFromData(NSData deviceToken) {
5455
public int Badge {
5556
get {
5657
if (CurrentInstallationController.IsCurrent(this)) {
57-
SetProperty<int>((int)UIApplication.SharedApplication.ApplicationIconBadgeNumber);
58+
RunOnUIQueue(() =>
59+
SetProperty<int>((int)UIApplication.SharedApplication.ApplicationIconBadgeNumber)
60+
);
5861
}
5962
return GetProperty<int>();
6063
}
6164
set {
6265
int badge = value;
6366
// Set the UI, too
64-
UIApplication.SharedApplication.ApplicationIconBadgeNumber = (nint)badge;
67+
RunOnUIQueue(() => {
68+
UIApplication.SharedApplication.ApplicationIconBadgeNumber = (nint)badge;
69+
});
6570
SetProperty<int>(badge);
6671
}
6772
}
73+
74+
/// <summary>
75+
/// Runs (synchronously) the on user interface queue.
76+
///
77+
/// Note that this could cause deadlocks, if the main thread is waiting on
78+
/// the background thread we're calling this from.
79+
///
80+
/// However, Xamarin's native bindings always threw exceptions when calling
81+
/// into UIKit code from a background thread, so this at least helps us in
82+
/// some deadlock scenarios.
83+
/// </summary>
84+
/// <param name="action">Action.</param>
85+
private static void RunOnUIQueue(Action action) {
86+
if (NSThread.IsMain) {
87+
action();
88+
} else {
89+
DispatchQueue.MainQueue.DispatchSync(action);
90+
}
91+
}
6892
}
69-
}
93+
}

0 commit comments

Comments
 (0)