-[UIApplication delegate] must be called from main thread only - ios

This warning leads to a serious problem cause I really can't call the delegate outside of the main thread using Xcode 9 beta 2. Strange thing is that this was working when I was using Xcode 8.3.3.
Also I thought it would only be good practice to call delegates from main thread only, isn't it? So why is this causing the app to crash now?

Just call it from the main thread like this.
Objective-C
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication delegate] fooBar];
});
Swift
DispatchQueue.main.async {
YourUIControlMethod()
}
Reaching out to your app delegate like this, is a hint that your architecture could use a little cleanup.
You can call delegates from any thread you want. You only need to make sure you're on the main thread for UIKit calls.
Or that you're on the correct thread your CoreData objects expect. It all depends on the API contract your objects have.

In Swift, you could also use DispatchQueue.main.async to call the UI controlling method from the main thread
DispatchQueue.main.async {
YourUIControlMethod()
}

Related

iOS app is crashing on ios 13 and with Xcode 11 when it didn't before

Our app is crashing with the fatal exception:
Fatal Exception: NSInternalInconsistencyException
Modifications to the layout engine must not be performed from a background thread after it has been accessed from the main thread.
Our app used to not throw this exception on previous versions of iOS (12 and below) and when I would compile on Xcode 10. Now, on iOS 13.3.1 and compiling on Xcode 11.3.1 our app crashes 10 seconds after opening every time. I looked into this exception and it seems Apple has decided to prevent apps from accessing the UIKit on background threads (please correct me if I'm wrong here). After enabling the Main Thread Checker I was able to pinpoint the line that was causing this crash. Backtracing the code led me to this line:
dispatch_async(dispatch_get_main_queue(), ^{
//Code that uses the StoreKit to retrieve purchase data,
//then updates the UI using UIKit based on this information
});
This code is fine though right? Because even though it's dispatching this block of code, it's doing it to the main thread, so this shouldn't be the issue, correct? Well, even after moving this block of code out of the dispatch_async() function, it still crashes. So then I looked at the singleton for this class, which looks like this:
+(instancetype)sharedPurchaseManager
{
static PurchaseManager * sharedPurchaseManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedPurchaseManager = [[PurchaseManager alloc] _init];
});
return sharedPurchaseManager;
}
And I wondered if the _init() for the PurchaseManager was happening in a background thread. So I tried moving the allocation for PurchaseManager out of the dispatch_once() block and the app stopped crashing. Furthermore, the Main Thread Checker stopped interrupting the program at the line that uses UIKit. I'm pretty sure that moving my _init() code out of the dispatch_once() block is not the correct way to go about fixing my issue, as this is the standard singleton design pattern (please correct me if I'm wrong). So then how should I go about fixing this issue? Furthermore, we have about 10+ crashes in our code that is due to the same exception, and with a similar design pattern to our PurchaseManager, so we would want a solution for all of these exceptions.
It sounds like [[PurchaseManager alloc] _init] contains some UI code, but +(instancetype)sharedPurchaseManager is accessed first time from background thread.
So you can try two approaches:
1) find the way explicitly initialize sharedPurchaseManger on the main thread (eg. in applicationDidFinishLaunching)
2) try to use the following
dispatch_once(&onceToken, ^{
dispatch_sync(dispatch_get_main_queue(), ^{ // << intentionally synchronous!
sharedPurchaseManager = [[PurchaseManager alloc] _init];
}
});

UIApplication delegate must be used from main thread only - Swift

I am getting "runtime: UI API called from background thread: -[UIApplication delegate] must be used from main thread only
" runtime issue for Fabric initialisation line. Not sure how to solve it. Please help
Thanks
Fabric.with([Crashlytics.self,Zendesk.self])
It's because you are trying to access the UI from background thread. Just call the UI change in main thread.
DispatchQueue.main.async {
application.statusBarStyle = UIStatusBarStyle.lightContent
}
UI process are maintained under main thread.

Why would you need a DispatchQueue when showing Alerts on Swift?

I am new to Swift, and trying to examine a finished project. But there is something i couldn't understand.
After a network request is completed, the app show an alert under a condition.
func makeNetworkRequest() {
//newtork result...
DispatchQueue.main.async {
self.showAlert(versionMessage: "Error")
}
}
func showAlert(versionMessage: String) {
let alert = UIAlertView(title: "", message: versionMessage, delegate: self)
alert.show()
}
However, it is done with a DispatchQueue. Why would anyone need to use DispatchQueue in this situation.
It’s a conscious design decision from Apple’s side to not have UIKit
be thread-safe. Making it thread-safe wouldn’t buy you much in terms
of performance; it would in fact make many things slower. And the fact
that UIKit is tied to the main thread makes it very easy to write
concurrent programs and use UIKit. All you have to do is make sure
that calls into UIKit are always made on the main thread. So
according to this the fact that UIKit objects must be accessed on
the main thread is a design decision by apple to favor performance.
for more detailed information you can go through this article
https://www.objc.io/issues/2-concurrency/thread-safe-class-design/
In your case , You are showing alert from another thread so you have to write code under the MainThread so , you can get the main thread using below code
DispatchQueue.main.async {
// Your UI Updation here
}
Reason
In Cocoa Touch, the UIApplication i.e. the instance of your application is attached to the main thread because this thread is created by UIApplicatioMain(), the entry point function of Cocoa Touch. It sets up main event loop, including the application’s run loop, and begins processing events. Application's main event loop receives all the UI events i.e. touch, gestures etc.
You´ll for sure notice that the alert will lag if you don´t show the alert on the main thread, that´s because your UI code does always have to be done on your main thread.
So if you're on a background thread and want to execute code on the main thread, you need to call async(). That´s way you call DispatchQueue.main, which is the main thread.

Any way to guarantee a code will always be executed on the main thread?

Excuse me if this question sounds stupid but this is beyond my knowledge of Objective-C.
I am developing some classes that have to always be executed on the main thread.
Ok, I can pollute my code with a bunch of
dispatch_async(dispatch_get_main_queue(),
^{
});
but I would like to know if there is something I can do to prevent the methods of this class from running on other threads that is not the main or to at least warn during debugging, compiling, or whatever if they are used not on the main thread.
thanks
I sprinkle such methods with my BLOCK_UI() macro from https://github.com/gradha/ELHASO-iOS-snippets. At runtime the macro will assert if the method is not running on the main thread. The macro goes away in release builds because I consider calling such an API in the background a programmer error, but if you want to make an API which is permissive with the programmer, you can also check for the main thread and invoke yourself in the main thread if needed. Example:
if ([NSThread isMainThread]) {
[self do_request:url];
} else {
[self performSelectorOnMainThread:#selector(do_request:)
withObject:url waitUntilDone:NO];
}
You can always check via the helpful API "[NSThread isMainThread]"

iOS: Is [UIApplication schedulelocalnotification] and related local notification manipulating methods thread safe?

My App sometimes need to schedule almost 64 local notifications, which will block my main thread for almost 1 seconde on iPhone4.
I want to do this on a separated thread, is these local notification manipulating methods of UIApplcation thread safe?
dont think so as the docs dont explicitly state it and UIKit in general in large parts isnt thread safe
but it would be worth a try :D the main thread is only a dispatch_async away ;)
--- maybe it would be an option to schedule them individually and run the main loop in between
There are two things in play, thread safety and calling UIKit from background threads. Some UIKit code doesn’t like to be called from a background thread at all and will throw an exception if you attempt to do so (like setting a new content for a UITextView). In other words, there’s something like this in the code:
NSParameterAssert([NSThread isMainThread],
#"This method must be called from the main thread.");
Then comes the thread safety, ie. if the code can be called from a background thread, it might still be written in a way that may result in a bug when you do so:
- (void) doA {
for (id item in allItemsArray) {
// do something
}
}
- (void) doB {
[allItemsArray addObject:#"foo"];
}
Now if one thread calls -doA and another thread calls -doB in the meantime, your app would crash with an exception because you changed the allItemsArray while enumerating it.
So the first question is if the notification methods can be called on a background thread. I’d say they can. In that case you can simply schedule all your notification from a background queue:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (int i=0; i<64; i++) {
// schedule notification
}
});
You don’t need to care about thread safety, unless there’s another part of your app scheduling other local notifications in the meantime. If there is, you can either create a separate queue to serialize all the notification calling code, or you have to be sure that the methods are thread-safe indeed (in which case I have no authoritative resource to offer).

Resources