Thread safety of UIImage - objective-c

I know that Apple officially recommends UIKit to be used in the main thread only. However, I've also heard claims that UIImage is thread-safe since iOS 4.0. I cannot find any documentation backing this claim.
Does anyone have any information to support this claim? As a class used to store data and decode image data, UIImage should be thread-safe if well designed.

Directly from Apple's documentation for UIImage
Image objects are immutable, so you cannot change their properties after creation. This means that you generally specify an image’s properties at initialization time or rely on the image’s metadata to provide the property value. It also means that image objects are themselves safe to use from any thread. The way you change the properties of an existing image object is to use one of the available convenience methods to create a copy of the image but with the custom value you want.
(Emphasis mine)
So at least in the current version of the SDK as of May 13, 2014, "image objects are themselves safe to use from any thread."

It is true that apple recommends using elements from the UIKIt on the main thread:
Note: For the most part, UIKit classes should be used only from an
application’s main thread. This is particularly true for classes
derived from UIResponder or that involve manipulating your
application’s user interface in any way.
Since UIImage isn't derived from UIResponder, and you do not actually display it on the interface/screen. Then doing operations with UIImages on another thread should be safe.
This is however based on my experience, I haven't seen any official documentation about it.

It looks like Apple have updated their documentation since the earlier answers here were posted. According to the most up-to-date documentation, it is safe to create and use UIImage instances from any thread:
Because image objects are immutable, you cannot change their
properties after creation. Most image properties are set automatically
using metadata in the accompanying image file or image data. The
immutable nature of image objects also means that they are safe to
create and use from any thread.
https://developer.apple.com/reference/uikit/uiimage

In the What's New in iOS: iOS 4.0 release notes, the UIKit Framework enhancements include this bit:
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.
So UIImage is thread-safe on iOS 4.0 and later.

Just to make it short:
UIImage is not thread safe, or better does only work on the main thread,
as I have experienced in my current after some debugging.
I hope that helps.
I wish to have more clarity about this from Apple
or even better an UIImage class, that could be rendered in a different thread.
Shouldn't be too difficult ...
edit:
After some research, I found that it is "UIGraphicsGetImageFromCurrentImageContext();"
that causes the trouble.
it's a bit off the topic, but maybe this helps:
https://coderwall.com/p/9j5dca
Thanks to Zachary Waldowski.

Thread-safe is not the issue, in that any thread can attempt to access a context at the same time (concurrently). And, while that is generally okay, in low-memory situations, like with a Photo Editing Extension on iOS devices, two threads accessing one context can crash an app due to low memory.
This happens when mixing Core Image filters with vImage operations. Both are thread-safe, but ARC will not release vImage buffer data before processing a Core Image object, so you have at some point two copies of an image in memory.
Accordingly, you never consider your knowledge of thread safety to be complete without understanding of threading and concurrency—and that goes double for any answer to questions about thread safety. In short: the proper question is, how does thread-safety apply to memory usage, whenever you're talking about image processing.
If you're just kicking the tires here, you need to wait to pose your question until you've encountered a real problem. But, if you're planning your next move, you need to know how to execute image processing commands sequentially, and with manual deallocation. You must design your app so that there is only one copy of the image being processing in memory. Never rely on automatic deallocation—thread-safe or not—to make that call for you. IT WILL NOT WORK.

Related

Objective-C atomic operations/locking access to myLocation property in Google Maps iOS SDK

This is partly a question regarding the Google Maps SDK in iOS, though perhaps mostly a question about atomic operations in Objective-C.
In my app, I wish to draw a GMSPolyline on a map between the user's current location and a selected destination. I can retrieve the user's current location using the myLocation property on a GMSMapView. According to the documentation for myLocation:
If My Location is enabled, reveals where the user location dot is
being drawn.
If it is disabled, or it is enabled but no location data is available,
this will be nil. This property is observable using KVO.
I have code to draw the polyline which takes the form:
if (myMapView.myLocation) {
// draw polyline between myMapView.myLocation and the selected destination
}
My concern is that, however remote the possibility, that between the check if (myMapView.myLocation) and drawing the polyline // draw polyline between myMapView.myLocation and the selected destination, myMapView.myLocation might become nil if the location is lost at an inopportune moment.
So my question is, in Objective-C, is there a way for me to wrap both the check that myMapView.myLocation is not nil and drawing the polyline into an operation which locks access to myMapView.myLocation, so it can't be changed after the check but before attempting to draw the polyline. If Objective-C does provide a mechanism, what affect does this have if the Google library does attempt to update myLocation while it is locked? Does the update just get queued until I've finished drawing the polyline and release the lock?
So I guess this is mostly a question about atomic transactions in Objective-C, in the context of the Google Maps library.
I don't know specifically for Objective C, but based on locking in other languages, I think what you want could only work if it was done in cooperation with the third-party library (ie Google Maps).
So for example if you were to somehow lock myMapView.myLocation while using it, this would only work if the Google Maps SDK also promised to lock it while modifying it, with the same lock object that you are using. Since myMapView.myLocation can be nil, this would be unlikely to work since you couldn't use a nil object as the 'key' to lock.
Similarly if you could lock the entire GMSMapView, such that none of its properties could change while the lock was held, this could only work if the Google Maps SDK promised to take the same lock before making any modifications.
In general, it's probably not a good idea to lock arbitrary objects from third-party libraries, as this might interfere with that library's own synchronization (unless the library explicitly offers this as part of its interface). Vice versa, when writing a library for use by third parties, it's best not to implement internal locking on objects which the library makes public - instead locking should usually be implementated on internal objects - just in case a user of the library tries to lock the public object.
In your case though, you could avoid the problem by doing this:
CLLocation* location = myMapView.myLocation;
if (location)
{
// draw polyline between location and the selected destination
}
That way even if the map view sets its .myLocation property to nil in between your check and your draw, you will still have a reference to the CLLocation, which can't be set to nil.
Note though that the documentation says:
GMSMapView can only be read and modified from the main thread, similar
to all UIKit objects. Calling these methods from another thread will
result in an exception or undefined behavior.
It seems likely that GMSMapView would honour the same requirement and so only modify its public properties from the main thread. So if your code is running in the main thread (which it has to), its unlikely that the map view's properties will change in the middle of your code running.

Is it safe to use managed objects loaded in background by performBlock: in main thread?

I'm creating my managed object context with NSPrivateQueueConcurrencyType concurrency type.
Also I'm using performBlock: selector to execute operations in background. So If I'm fetching some objects in background (in performBlock:), is it safe to use resulting managed objects in main thread?
As a general rule, no it is not safe to share NSManagedObject instances across threads no matter what concurrency type you are using.
However there is a library you can use to make your context(s) and object instances thread-safe. With that you can pretty much ignore all the nonsense about ensuring thread isolation between contexts and focus your efforts on the things that matter, like building out the actual functionality of your app.
I'm not 100% sure, but in my own experience I do it this way: If you are changing the variables properties, do it inside performBlock. I had one case where reading was causing some weird behavior, but in general it seems to be OK. If you want to be extra safe, use performBlock every time you touch a managed object in any way.
You will need to use a different context for each thread as explained here iOS Developer - Core data multithreading
One way to implement is described at Core Data - one context per thread implementation
Sorry, I should've search better, here is exactly my question & answer to it:
Core Data's NSPrivateQueueConcurrencyType and sharing objects between threads

Debug thread safety issue on iOS

I've got a thread safety bug somewhere in a fairly large set of code. It's reproducible as a random crash simply by scrolling around in my CATiledLayer for a few seconds in the simulator, and solvable by locking my drawing code into a single thread (which is not ideal, since CATiledLayer is designed to be multi-threaded and my drawing code is slow enough to need it).
How do I go about debugging a thread safety issue? I suspect it's somewhere in my code to lazily fetch (and cache) the data which is being drawn, but that doesn't narrow it down much.
I've skim read the Concurrency Programming Guide, but don't see anything that talks about debugging, it just talks about how to structure your code.
Which concurrency method do you use? GCD or NSThread? And if I can't convince you to use single thread for drawing, try to use #syncronized in your setter/getter methods (or atomic properties, if you use synthesized setters/getters).

does [NSFont systemFontOfSize] memory needs to be released

I am trying to lower the footprint of memory my application uses at runtime....
In the standard usage to get a font based on system font size the api is used as font = [NSFont systemFontOfSize]
+ (NSFont *)systemFontOfSize:(CGFloat)fontSize; // Aqua System font
As per my understanding that the font will be freed by the autorelease pool, First I need to confirm that this understating is correct?
If this is correct, then if I have a drawWithFrame function where I am using this every time I draw a cell. Should I not release it there? and would increasing the memory footprint of the application, since the fonts would be freed when the applications autorelease pool is called?
Now is again this understanding is correct? There are 2 approaches
Find a way to release NSFont
Put a NSAutoReleasePool *pool. alloc / release there itself in draw with frame
What do you guys suggest?
The function name systemFontOfSize: doesn't begin with any of the magic keywords "alloc", "new", "copy", or "mutableCopy", so you aren't responsible for releasing what it returns. See the Cocoa basic memory management rules for details.
I'm not use to dealing with Font so I might be out of the way.
But to me if you frequently need and object, I would cache it in a property.
Creating and deletion is more expensive than reading a property.
And if this is a key feature of your class, I would event create it in the init of my class.
That would save the unnecessary test to see if it already exist.
You are correct on both items. By convention, all named initializers return autoreleased objects. Since you (scope of drawWithFrame) did not excplicitly allocate font you are not responsible for releasing it. Like you also suggested, this can be optimizated by putting an autorelease pool around it.
Wether or not the benefit is worth the extra typing work of the coder is debatable.
As with most non-"init" methods that return an object ("copy" is an exception that pops to mind) the object returned by systemFontOfSize is autoreleased and so it will be released at some point in the (very near) future.
If you want to use the object pointed to by your variable "font" outside of the local scope you should retain it and release it when it's no longer needed (or before being replaced by another font)
Edit: I just reread realized you're creating the font every time so the 2nd paragraph isn't so relevant to your question, but anyway, unless the font is something that has to change many times a second I'd consider creating the font object outside the drawrect method. I don't know how much of a practical effect this specifically would have on your current FPS/responsiveness but it's generally good to get used to not doing stuff such as object creation redundantly multiple times in loops etc.

Can Vertex Array Objects (VAOs) be shared across EAGLContexts in OpenGL ES?

Spoiler: I'm fairly confident that the answer is NO, but that's only after a day of very frustrated debugging. Now I would like to know if that is indeed the case (and if so, how I might have known), or if I'm just doing something completely wrong.
Here's the situation. I'm using OpenGL ES 2.0 to render some meshes that I load from various files (.obj, .md2, etc.). For the sake of performance and User Experience, I delegate the actual loading of these meshes and their associated textures to a background thread using GCD.
Per Apple's instructions, on each background thread, I create and set a new EAGLContext with the same shareGroup as the main rendering context. This allows OpenGL objects, like texture and buffer objects, that were created on the background thread to be immediately used by the context on the main thread.
This has been working out splendidly. Now, I recently learned about Vertex Array Objects as a way to cache the OpenGL state associated with rendering the contents of certain buffers. It looks nice, and reduces the boilerplate state checking and setting code required to render each mesh. On top of it all, Apple also recommends using them in their Best Practices for Working with Vertex Data guide.
But I was having serious issues getting the VAOs to work for me at all. Like I do with all loading, I would load the mesh from a file into memory on a background thread, and then generate all associated OpenGL objects. Without fail, the first time I tried to call glDrawElements() using a VAO, the app crashes with EXC_BAD_ACCESS. Without the VAO, it renders fine.
Debugging EXC_BAD_ACCESS is a pain, especially when NSZombies won't help (which they obviously won't), but after some time of analyzing captured OpenGL frames, I realized that, while the creation of the VAO on the background thread went fine (no GL_ERROR, and a non-zero id), when the time came to bind to the VAO on the main thread, I would get a GL_INVALID_OPERATION, which the docs state will happen when attempting to bind to a non-existent VAO. And sure enough, when looking at all the objects in the current context at the time of rendering, there isn't a single VAO to be seen, but all of the VBOs that were generated with the VAO AT THE SAME TIME are present. If I load the VAO on the main thread it works fine. Very frustrating.
I distilled the loading code to a more atomic form:
- (void)generate {
glGenVertexArraysOES(1, &_vao);
glBindVertexArrayOES(_vao);
_vbos = malloc(sizeof(GLuint) * 4);
glGenBuffers(4, vbos);
}
When the above is executed on a background thread, with a valid EAGLContext with the same shareGroupas the main context, the main context will have 4 VBOs, but no VAO. If I execute it on the main thread, with the main context, it will have 4 VBOs, and the VAO. This leads me to the conclusion that there is some weird exception to the object-sharing nature of EAGLContexts when dealing with VAOs. If that were actually the case, I would have really expected the Apple docs to note that somewhere. It's very inconvenient to have to discover little tidbits like that by hand. Is this the case, or am I missing something?
According to this, OpenGL-ES explicitly disallows sharing of VAO objects:
Should vertex array objects be sharable across multiple OpenGL ES
contexts?
RESOLVED: No. The OpenGL ES working group took a straw-poll and
agreed that compatibility with OpenGL and ease of implementation
were more important than creating the first non-shared named object
in OpenGL ES.
As you noted, VBOs are still shareable, so you just have to create a VAO for each context that binds the shared VBO.