60

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?

renraku
  • 851
  • 1
  • 9
  • 16
  • 1
    Apparently you are doing it from another thread. We can't help you if you don't share some code. – phi Jul 13 '17 at 13:28
  • 3
    Just because the code *worked* doesn't mean that it was right. With threading issues, it may "work" 9999/10000 times, but that last failure will often happen in the hands of a reviewer. ;) – bbum Jul 13 '17 at 17:24
  • Also check in the stack trace that it's your code and not some third-party library. – Artem Abramov Jul 13 '17 at 23:09

2 Answers2

89

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.

orkoden
  • 18,946
  • 4
  • 59
  • 50
  • Just wondering what exactly you mean by the architecture cleanup. Say for instance I have a reference to the current context used by CoreData. I access it through my AppDelegate. Where should I put it instead? – el-flor Oct 03 '17 at 06:59
  • 2
    You make separate object that wraps all your CoreData code. Then you pass that object around (dependency injection) to the view controllers that need them. – orkoden Oct 04 '17 at 14:00
  • 4
    The "architecture cleanup" here refers to the fact that you should almost never reference `[[UIApplication sharedApplication] delegate]` anywhere in your code. The app delegate is the *UIApplication's delegate*. It isn't a dumping ground for global storage. If you want a singleton to hold whatever you're holding here, create a new singleton. Your app delegate code should generally be fairly short, and focused only on application state transitions, not storing your model. – Rob Napier Nov 09 '17 at 13:52
  • 1
    [But the app delegate is the closest thing to the CPU!](https://twitter.com/realbadiostips/status/866930271399981056?lang=en) (This is a joke, future reader who is unsure about iOS.) – royalmurder May 15 '18 at 09:50
25

In Swift, you could also use DispatchQueue.main.async to call the UI controlling method from the main thread

DispatchQueue.main.async {
    YourUIControlMethod()
}
Allen
  • 2,979
  • 1
  • 29
  • 34