Reputation: 14298
Is calling something like this considered thread safe ? It's only creating a UIImage, no UI updating. I can't find any documentation about this.
UIImage * hiResImage = [[UIImage alloc] initWithContentsOfFile:path];
FYI, I later do the UI update on main thread like this...
[imageViewForZoom performSelectorOnMainThread:@selector(setImage:) withObject:hiResImage waitUntilDone:NO];
What I already know:
[myImageView setImage:image];
)EDIT: Let's look at another point of view. Does 'not-thread-safe' means that there is a chance that it can be blocked forever? or just means there is no guarantee on the start/duration execution time. If it is the latter case, then there is no problem if we would have some 'undetermined amount' of delay when loading an image. The UI update is done on main thread. So, it is still considered OK, for creating UIImage at least, to be not-thread-safe.
I know this is not really related to the question but just want to point it out since I fear there will be no clear-cut answer to my original question :)
Upvotes: 4
Views: 3397
Reputation: 902
According to Apple, the answer is yes, it is safe to create a UIImage 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
Upvotes: 2
Reputation: 166
My experience below is not directly with UIImage initContentsFromFile:
but with UIImage imageWithData
, but your question is about UIImage thread safety.
I recently had to debug an issue with using [UIImage imageWithData:]
that is called from a NSURLConnetionDelegate
function connectionDidFinishLoading
to download images using several background threads. Since the downloaded images are used for updating the UI, I had to use [NSOperationQueue mainQueue] addOperationWithBlock ...
below:
- (void) connection:(URLConnection*)connection didReceiveData:(NSData *) data {
[imgData appendData:data];
}
- (void) connectionDidFinishLoading:(NSURLConnection*)connection {
[NSOperationQueue mainQueue] addOperationWithBlock:^{
UIImage *img = [UIImage imageWithData:imgData];
// more code here to update the UI
}];
}
img
holds a valid imageimg
is always nil
During a debugging session, I noticed that the issue (temporarily) disappeared when the debugger stepped through each statement one line at a time. My theory is that running in debugger step-mode does not put UIImage
to handle concurrent threads running imageWithData
. Therefore, I believe that UIImage imageWithData
(and perhaps other similar functions) are not thread-safe.
Using a @synchronized
block seems to solve the issue
- (void) connectionDidFinishLoading:(NSURLConnection*)connection {
[NSOperationQueue mainQueue] addOperationWithBlock:^{
@synchronized(imgData) {
// Run the following in a synchronized block
UIImage *img = [UIImage imageWithData:imgData];
}
// more code here ....
}];
}
Upvotes: 4
Reputation: 1586
Yes. It is fairly common practice to load images in the background, mainly if its a remote file, or if many images are being loaded. And yes, only update UI on the main thread.
EDIT:
Due to some enlightening comments, I would revise my first answer of 'Yes' to 'Based on experience and my assessment of what wouldn't be a viable alternative for UIImage's thread safety when it comes to loading an image, I think it's reasonable to assume it is. However, each person is warranted their own opinion, and perhaps his or her risk associated with code failure here is too high to make assumptions under any circumstances.'
Upvotes: 1