Based on a previous discussion I had in SO (see Doubts on concurrency with objects that can be used multiple times like formatters), here I'm asking a more theoretical question about objects that during the application lifetime are created once (and never modified, hence read-only) and they can be accessed from different threads. A simple use case it's the Core Data one. Formatters can be used in different threads (main thread, importing thread, etc.).
NSFormatter
s, for example, are extremely expensive to create. Based on that they can created once and then reused. A typical pattern that can be follow (also highlighted by @mattt in NSFormatter article) is the following.
+ (NSNumberFormatter *)numberFormatter {
static NSNumberFormatter *_numberFormatter = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_numberFormatter = [[NSNumberFormatter alloc] init];
[_numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
});
return _numberFormatter;
}
Even if I'm sure that is a very good approach to follow (a sort of read-only/immutable object is created), formatters are not thread safe and so using them in a thread safe manner could be dangerous. I found a discussion on the argument in NSDateFormatter crashes when used from different threads where the author has noticed that a crash could happen.
NSDateFormatters are not thread safe; there was a background thread attempting to use the same formatter at the same time (hence the randomness).
So, what could be the problem in accessing a formatter from different threads? Any secure pattern to follow?
Specific answer for formatters:
Prior to iOS 7/OSX 10.9, even read-only access to formatters was not thread-safe. ICU has a ton of lazy computation that it does in response to requests, and that can crash or produce incorrect results if done concurrently.
In iOS 7/OSX 10.9, NSDateFormatter
and NSNumberFormatter
use locks internally to serialize access to the underlying ICU code, preventing this issue.
General answer:
Real-only access/immutable objects are indeed generally thread-safe, but it's difficult-to-impossible to tell which things actually are internally immutable, and which ones are merely presenting an immutable interface to the outside world.
In your own code, you can know this. When using other people's classes, you'll have to rely on what they document about how to use their classes safely.
(edit, since an example of serializing access to formatters was requested)
// in the dispatch_once where you create the formatter
dispatch_queue_t formatterQueue = dispatch_queue_create("date formatter queue", 0);
// where you use the formatter
dispatch_sync(formatterQueue, ^{ (do whatever you wanted to do with the formatter) });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With