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
Related
I have a large application that uses a number of third-party libraries and am now seeing the following error in the logs: "This application is modifying the autolayout engine from a background thread after the engine was accessed from the main thread. This can lead to engine corruption and weird crashes."
From what I have found here on SO, this is probably being caused by a UI element being changed on a background thread, which is triggering the autolayout. Unfortunately, we have so many UI elements being changed by so many different moving parts that I do not know the best way to find the culprit.
Can anyone tell me how can I found out what exactly is triggering the autolayout change from a background thread?
Sometimes it's not a completion block, but anything that is performed in the background.
In my case it was notifications that where sent. I implemented iCloud in my app, which means that when data was edited or added on another device, the other app(s) receive an iCloud update/notification, which triggered an update of the UITableView.
The code to update the UITableView was not done in the MainThread. Adding the code as shown in the comments fixes it.
How would I constantly refresh a background image of my UIImageView, while also still listening for touches and input? What I am looking for is the iOS Objective C equivalent (in java) of creating a new thread apart from the main thread, and having that thread be devoted to updating the background picture as fast as possible. Thanks!
It depends on where the new images are coming from. If they are a cycle of known existing images in your app bundle, just make this an animated image view (or an animated image) and the cycle will happen automatically.
If you need to run code e.g. to get out to the network periodically, then just start a repeating NSTimer. It calls you on the main thread, but your main thread code will be very brief indeed, and networking takes place asynchronously (unless you mess that up deliberately). Just make sure that when you actually set the image, you step out to the main thread, as you must never touch the interface in any way except on the main thread.
I have an iOS application that has an NSTimer which fires every 5 seconds. This then posts a notification, telling several controllers that they must now recalculate some data and then update their UI.
When this all happens on the main thread, scrollviews can become jittery as the data is processed.
Using GCD, I have wrapped the code called when a notification is posted:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Code here
dispatch_async(dispatch_get_main_queue(), ^(){
// Reload tableviews and UI
};
};
Unfortunately, this leads in certain cases to several threads accessing the same instance variables. This causes my application to crash as sometimes it ends up mutating an array being enumerated in another thread.
Wrapping the code in a synchronised block prevents this.
When the user scrolls the tableview, several methods are called to calculate the height etc, on the main thread. The code within the background thread is working on the code needed by the main thread. As such, this can usually further cause crashes
I have tried setting the variables to 'atomic', but this doesn't solve the issue. Ideally, I don't want to have the main thread waiting on the background thread, but I am not sure how to best resolve this issue given that they need the same data?
This is pretty classic multithreaded programming issues. There are a number of ways to solve it with basic locks (#synchronized blocks), reader/writer locks, etc but the problem is often that you can't control when the user is going to scroll or take other action. If you #synchronize, you have to do it anywhere that data is touched, including your UITableView data source methods. That can lead to stuttering if the background processing happens to be in the middle of something.**
Personally, I would use an immutable snapshot mechanism.
Have the background thread produce the results, then include just the data the UI needs to display in the notification data as an immutable snapshot (copy). That way the background thread never modifies the data the UI is currently reading for display. How you would implement this is highly dependent on how much data you are talking about and the form it takes, but the safe way would be to have copies of your classes with readonly properties. Alternatively, you can use a "frozen" flag. Make a copy, then set frozen = YES on the copy. The UI thread will only ever see "frozen" or readonly objects coming from the background thread.
The benefit is the UI never causes the background thread to stall and there are no locks required. The downside is increased memory usage, though if the amount of data is large you can use copy-on-write mechanisms to allow the background thread and UI thread to share the data, even though logically the UI thread has a completely separate copy.
** Note: In most applications, you don't have this sort of continuous background processing going on so those apps can use simpler mechanisms. This is typically a form of message passing where the background thread finishes its task and "passes the message" to the UI thread (passes the results). At that point the background work is finished so there is no concurrent modification happening.
For better performance on scrolling the UItableView. I was adviced to draw the cells in a background thread.
But some one said that, update UI in background thread is not recommended, this can crash the app.
Is it possible to draw cells in background thread?
You very well can draw on a background thread - and then capture that drawing as an image and send that back to the main thread; there an image view displays the image you draw in the background.
If you have access to the Apple developer site, watch the WWDC 2012 Video "Building Concurrent User Interfaces on iOS". You don't want to actually lay out UIView instances and so forth but just use the various Core Graphics drawing functions.
You can not do that , every view would draw itself at the time when it comes to foreground, it would do nothing in background.
Drawing UI in background not only can crash but in most cases will crash the app.
Make sure you're using dequeueReusableCellWithIdentifier: message for getting cells.
Revise your tableView:cellForRowAtIndexPath: delegate to find what consumes most resources. It could be, e.q. hard UIImage processing or something similar. You should consider move all the processing, generating data and such things out of your cell creating. Only set appropriate data in cell and return it. I'm pretty sure it'll reduce your performance issues greatly.
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]