What Needs To Be on Main Thread? - ios

I have written a little define called ensureInMainThread (and I use it quite a bit). However, I'm not sure exactly which user interface methods require being called on the main thread. What about setNeedsDisplay and setNeedsLayout? What is the rule of thumb for methods that need to be called on the main thread in iOS 5.x?
These questions are related (some low quality questions and answers, and some very case specific), but I would like a comprehensive, single good answer:
UIView setNeedsDisplay Not on main thread?
Does UIView's -drawRect: have to be called on the main thread?
Make UIImage From UIView but NOT in the main thread

As of iOS 4.0, some user interface updates can be performed on a background thread:
Drawing to a graphics context in UIKit is now thread-safe. Specifically:
The routines used to access and manipulate the graphics context can now correctly handle contexts residing on different threads.
String and image drawing is now thread-safe.
Using color and font objects in multiple threads is now safe to do.
David Duncan confirms this in his comments here.
Beyond that, pretty much everything else regarding UIKit is not considered threadsafe, so you should make sure you are interacting with it on the main thread in those cases.
As an aside, I do prefer my block-based implementation of a "always run on the main thread" function over the macro you link to, because I like the explicit wrapping of code that needs to be run on the main thread.

Rule of thumb: Anything that updates the interface must be on the main thread.

With iOS 12, if you call setNeedsDisplay from a background thread, you get the following assert:
Main Thread Checker: UI API called on a background thread: -[UIView setNeedsDisplay]

Related

Ok to create UIView on background thread?

OK, normally I know it's not ok. But what if I know I'll never attach that view to the actual UI hierarchy - it's only used to generate a snapshot, or compute something, or whatever.
If it IS ok, how do I silence the Main Thread Checker: UI API called on a background thread console dump? (that console output is the reason I'm paranoid about doing this in the first place, now).
But what if I know I'll never attach that view to the actual UI hierarchy
I don’t think it matters what you know. The main thread checker presumably knows more. In the interface or not, UIKit interface objects are inherently not threadsafe. Do this on the main thread.

UIImageView setHighlightedImage: does it have to be on main thread?

I'm working to improve the performance of images displayed to the user. I have removed alpha blending and am assigning a scaled/correctly sized image to the UIImageView already along with some caching. However, also as a part of this I am thinking of moving setHiglightedImage: call to background thread.
ImageView is wrapped in UIKit which says that any modification to layouts should be done on main thread. However while assigning an image with a highlightedImage we're not triggering any layout changes or invoking any constraints. Would this be a valid change that doesn't violate UIKit rules? Are there going to be any exceptions thrown because of this?
I don't see any problems or warnings by debugger while running this so far on background thread. Also the apple's official documentation (here and here) around UIImageView doesn't specify anything about this being on background thread. I tried searching more online about doing this, but couldn't really find anything helpful
Is there any reason for [UIImageView setHighlightedImage:] to not be on background thread? Will it have any performance benefits?
setHighlightedImage is changing the user interface . You can not run it on a background thread.
In a Cocoa application, the main thread runs the user interface, that
is, all drawing and all events are handled on the main thread. If your
application performs any lengthy synchronous operations on that
thread, your user interface can become unresponsive and trigger the
spinning cursor. To avoid this, you should shorten the amount of time
consumed by those operations, defer their execution, or move them to
secondary threads.
Apple Documentation

UIView setFrame thread safety

The UIView docs say "Manipulations to your application’s user interface must occur on the main thread". Despite this, in my tests so far I have found that repositioning a view using setFrame from a background thread does work.
Can anyone confirm whether setFrame is thread safe?
All UI updating code ( including setFrame ) must be done on the main thread. I think you already know the answer to this :)
It may work in a background thread, but it doesn't mean it's safe.
To answer the question more directly, Apple pretty much says UIView code is not thread safe.
If you need to update the UI from a different thread, invoke it on the main thread using Grand Central Dispatch.
Here's a kind of similar question # stackoverflow

DrawRect not called due to active main thread

I have an architecture that takes input from the mic and then performs some calculations and then should render to screen.
The issue is that calling setNeedsDisplay never triggers a call to drawRect because the main thread is running the calculations.
What would be the best way to thread this?
Create a single serial queue and dispatch the work to this background queue using GCD and dispatch the final setNeedsDisplay back to the main queue, or is there a more efficient way of doing this?
keep everything long running off the main thread. that is best in my opinion. Long running calculations are also something
try to never block the UIThread
...work to this background queue using GCD and dispatch the final
setNeedsDisplay back to the main queue, or is there a more efficient
way of doing this?
Based on your pretty vague description, I'd say what you suggested is the best approach.
And if you do this with GCD, your code will be easy to read since the blocks of work you perform are inline in your code making it easy to understand what is going on.
Create a single serial queue and dispatch the work to this background queue using GCD and dispatch the final setNeedsDisplay back to the main queue, or is there a more efficient way of doing this?
You should use the highest level API available to you. In this case, it's NSOperation or one of its subclasses. Probably, NSBlockOperation is the one you want. You should
create a block operation with the block you want executing
Set its completion handler to invoke setNeedsDisplay
Stick it on an NSOperationQueue.
The completion handler needs to invoke setNeedsDisplay on the main thread. You can do this by sending performSelectorOnMainThread:withObject:waitUntilDone: to the view e.g.
[myViewThatNeedsUpdating performSelectorOnMainThread: #selector(setNeedsDisplay)
withObject: nil
waitUntilDone: NO];
I think this is a better approach than using GCD directly because it is more in the Objective-C idiom, it separates the work you are doing from the notification at the end and gives you many more options for how things get done than raw GCD. For instance, if you want several of these things to happen sequentially, you can make some operations dependencies of others without having to write lots of code.

How do I prepare my UI in a background thread?

A UIViewController takes about half a second to load its contents and appear on screen. How can I make them all load in the background and appear when they're ready?
There is a LazyTableImages sample on the Apple developer site.
It shows how to perform the heavy lifting in a background thread and update the UI on the main thread.
PerformSelectorInBackground:withObject: is a possible solution, although a more modern method would be to use asynchronous blocks. You can run code on the main thread from within these blocks to update the UI Safely.
The Concurrency Programming Guide is a good place to find more information and examples of this.
A Background Thread cant update the UI,you can perform all the processing logic in background thread and call the main thread for UI update
Example to load a tableView with Data ,use the background thread to process everything and load the Data, call [tableView reloadData] using the main thread, see Grand central Dispatching to know how to Work with Threads in IOS..
Hope it Helps
Create a GCD queue to process your work in a background thread (read the docs, because my "create" label and options may not be what you want).
You send it to the queue asynchronously, meaning that the call to dispatch_async will make appropriate arrangements for the block of code you give it to run in another thread and it will then return back to you "immediately."
All the work in the block you give it will be executed on a separate thread. Note, at the end, you do another call, this time with the well know main queue. This arranges for that code to run in the main thread, which is mandatory for any UI work.
Also, you really should read the documentation on GCD and especially blocks, because there are memory and cycle considerations. Good luck.
dispatch_queue_t workQ = dispatch_queue_create("bgWorkQ", 0);
dispatch_async(workQ, ^{
// This code is now running in a background thread.
// Do all your loading here...
// When ready to touch the UI, you must do that in the main thread...
disptach_async(dispatch_get_main_queue(), ^{
// Now, this code is running in the main thread.
// Update your UI...
});
});
dispatch_release(workQ);
The easiest way is to use NSObject's - (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg You just pass it a selector and it will happy in the background and not block your UI. Be aware however that there are rules to background threads.
You shouldn't update your UI from the background thread. And you need to make sure the methods you're calling are thread safe.

Resources