-2

Whenever my application fetch data from JSON it sometimes get this warning and application freezes right away:

Main Thread Checker: UI API called on a background thread: -[UIApplication delegate]

PID: 7439, TID: 362794, Thread name: (none), Queue name: NSOperationQueue 0x60000002f7c0 (QOS: UNSPECIFIED), QoS: 0 Backtrace:

Can anyone explain how to get rid of it?

Community
  • 1
  • 1
shahtaj khalid
  • 476
  • 7
  • 24
  • can you please paste your code. Might be issue with thread. – Gagan_iOS Oct 26 '17 at 14:30
  • 1
    Please read [Under what circumstances may I add “urgent” or other similar phrases to my question, in order to obtain faster answers?](//meta.stackoverflow.com/q/326569) - the summary is that this is not an ideal way to address volunteers, and is probably counterproductive to obtaining answers. Please refrain from adding this to your questions. – halfer Oct 26 '17 at 16:17
  • @halfer It was urgent and i did got the hint right away from Rob's answer. – shahtaj khalid Oct 27 '17 at 05:51
  • 1
    My downvote, then, is a gentle reminder that we ask people not to plead for help here. Most people who respond to the above "don't beg" boilerplate tend to apologise, and thank me for revealing the community's views on the matter. – halfer Oct 27 '17 at 11:52

3 Answers3

4

It looks like you're updating something on the UI from a thread that's not the main thread.

There's not a lot to go on in your question. But if you're using JSON, you're probably retrieving it asynchronously. Make sure that whenever you update the UI from something retrieved, that you wrap it up in a call to the main thread through something like

dispatch_async(dispatch_get_main_queue(), ^{
// code to post to UI
});
George Brown
  • 1,134
  • 10
  • 25
2

In the latest versions of swift / Xcode / simulator even examining a UI control for a value can throw this.

There are a ton of questions and resources on this very topic. For instance:

Thorough Tutorial

SO Answer

But here's what I guess you want:

DispatchQueue.main.async {
    // Access UI stuff here
}
Damo
  • 12,840
  • 3
  • 51
  • 62
2

When ever my application fetch data from json

So you should start with the code that fetches that data. Somewhere you are probably calling [[UIApplication sharedApplication] delegate] on a background thread. That's not allowed.

This likely means you're using your application delegate as a place to store model data. You shouldn't do that. There's almost nowhere in an app that you should reference the application delegate. (This is a very common mistake because it's sometimes done in sample code for simplicity.)

If the program crashes, the location should be in the stacktrace, so I would start by looking there, but otherwise, you'll need to audit your code (likely around JSON parsing or network requests) to find where you're doing this.


As noted in the comments below, there is no quick fix to this, and you have almost certainly made your code less stable and more likely to crash in the field. That said, creating a singleton to hold global values in Swift looks like this:

class SomeSingleton {
    static let shared = SomeSingleton()
    // Properties you want to be available via the singleton
}

You access it with:

SomeSingleton.shared.<property>

This does not make anything thread-safe, but if the singleton's properties are immutable (let), then fetching them via SomeSingleton.shared can be safely called on any thread, unlike UIApplication.shared.delegate.

Again, it sounds like you have significant concurrency issues in this code, and this is not a quick fix; it is just one tool that is often used rather than putting random values on the AppDelegate.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • Yes i'm using this as context to save json in coreData. but that's how am i suppose to do that without it? – shahtaj khalid Oct 26 '17 at 15:10
  • class func getContext () -> NSManagedObjectContext { let appDelegate = UIApplication.shared.delegate as! AppDelegate return appDelegate.persistentContainer.viewContext } – shahtaj khalid Oct 26 '17 at 15:10
  • This is the context being called everytime i have to save json in Coredata – shahtaj khalid Oct 26 '17 at 15:11
  • 2
    And that's your problem. The application delegate is not the correct place to store the core data context. The application delegate is the delegate of the UIApplication. If you want a singleton to store the core data context, create a singleton; don't hijack AppDelegate. AppDelegate can only be accessed from the main thread, but core data often works on many threads. (note that the fact that this is called `viewContext` suggests you may be accessing this context on the wrong thread, too, however; "view" things generally belong on the main thread if you mean UIView). – Rob Napier Oct 26 '17 at 15:26
  • 1
    Worth noting, that core data contexts aren't thread safe either, and should only be accessed from the thread that created them. Even if you fix your app delegate problem, you'll get an error on the managedObjectContext if you try to modify the entities. – George Brown Oct 26 '17 at 17:49
  • Not just modify; even accessing is not thread-safe due to the possibility of faulting. – Rob Napier Oct 26 '17 at 19:04
  • I got it. but can you suggest me some quick code to replace this context? i'm really in a hurry!! – shahtaj khalid Oct 27 '17 at 05:19
  • I got it working by actually removing DispatchQueue.main.async from some places and removing from some parts.. Thanks alot anyways :) – shahtaj khalid Oct 27 '17 at 05:33
  • You've almost certainly introduced new race conditions with that change. When you start getting crashes from the field (likely in the Core Data stack), this will be the cause and you'll need to finish extracting this from AppDelegate and fix your multi-thread access of NSManagedObjects. – Rob Napier Oct 27 '17 at 15:33
  • There is no "quick code to replace this context." It depends on what your code is now and how you're accessing things. It's not possible to use Core Data in a multi-threaded environment without learning the Core Data concurrency rules. It is critical that you know what queue you're using for each part of your code; you cannot simply add and remove `async` calls until it seems to work. https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreData/Concurrency.html – Rob Napier Oct 27 '17 at 15:35
  • 1
    Gotta join in on this one, not sure what you've done, but it sounds absolutely terrible. I'm not really sure how removing asyncs to the main thread is going to help you at all except make the situation far worse. You should be fetching your JSON asynchronously, you could then update a core data stack in a background thread if configured properly, but then you will def need something that brings it back to the main thread for the UI. – George Brown Oct 28 '17 at 14:39