Can I share a single ACAccount instance between threads? Specifically I would like to create multiple TWRequest objects that are used by different NSOperationQueue instances. Those TWRequest objects will share a single ACAccount instance. Is that safe?
Thanks.
I'm going to say, "no." Firstly, ACAccount does not appear on Apple's "Thread Safe" list. Secondly, I see no explicit mention of thread safety in the reference for either of those classes. Thirdly, I see that TWRequest appears to be built upon NSURLConnection which is designed for use on a run loop (typically the main thread). I see nothing at all to indicate that these classes are safe for concurrent use from multiple threads. At best, you should take a thread-confinement approach (i.e. each thread fetches/creates its own copies of these objects and should not pass them between threads.)
Since TWRequest is designed for cooperative/runloop-based operation, I see no reason that you would need to do this stuff on a background thread either, FWIW.
So yeah. I'd say, "no."
Related
I am implementing some core data sample project. I have defined a mainManagedContext and a privateManagedContext.
Now my question is, "Is it right if I access privateManagedContext using multiple threads?"
Thank you in advance.
In my experience with accessing at the same time the static context lead me to a crashes.
So the only solution that I've implemented is to make a copy of the managedObjectContext for each tread where i have to work and make all my function( add/edit/save) with context as parameter:
so in some thread make a copy of context:
NSManagedObjectContext *localContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[localContext setPersistentStoreCoordinator:YourStaticManagedObjectContext.persistentStoreCoordinator];
and use that context in current thread (add/edit)
then save context:
[YourManager saveContext:localContext withBlock:nil];
be careful if you need data at the same time when write in one thread and read on other thread better to implement some synchronized access to that staticManagedObjectContext.
You'll want to refer to this guide:
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreData/Concurrency.html
In short, you generally can't refer to the same managed object context from multiple threads. Unless you set the concurrency policy accordingly. But, even then, you aren't going to get truly concurrent I/O operations (which is as designed because concurrent I/O is generally slower anyway, among other reasons).
What are you trying to do?
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.).
NSFormatters, 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) });
I'm asking a more theoretical question about objects that during the application lifetime are created once (and never modified, hence read-only)
That is not technically correct: in order for an object to be truly read-only, it must also be immutable. For example, one could create NSMutableArray once, but since the object allows changes after creation, it cannot be considered read-only, and is therefore unsafe for concurrent use without additional synchronization.
Moreover, logically immutable object could have mutating implementation, making them non-thread-safe. For example, objects that perform lazy initialization on first use, or cache state in their instance variables without synchronization, are not thread-safe. It appears that NSDateFormatter is one such class: it appears that you could get a crash even when you are not calling methods to mutate the state of the class.
One solution to this could be using thread-local storage: rather than creating one NSDateFormatter per application you would be creating one per thread, but that would let you save some CPU cycles as well: one report mentions that they managed to shave 5..10% off their start-up time by using this simple trick.
I want to use an NSOperationQueue to dispatch CoreData operations. However, operation queue behavior is not always the same (e.g. it dispatches using libdispatch on iOS 4.0/OS 10.6 which uses thread pools) and a queue might not always use the same thread (as NSManagedObjectContext requires).
Can I force a serial NSOperationQueue to execute on a single thread?
Or do I have to create my own simple queuing mechanism for that?
Can I force a serial NSOperationQueue to execute on a single thread?
Or do I have to create my own simple queuing mechanism for that?
You shouldn't need to do either of those. What Core Data really requires is that you don't have two pieces of code making changes to a managed object context at the same time. There's even a note on this at the very beginning of Concurrency with Core Data:
Note: You can use threads, serial operation queues, or dispatch queues for concurrency.
For the sake of conciseness, this article uses “thread” throughout to refer to any of these.
What's really required is that you serialize operations on a given context. That happens naturally if you use a single thread, but NSOperationQueue also serializes its operations if you set maxConcurrentOperationCount to 1, so you don't have to worry about ensuring that all operations take place on the same thread.
Apple decided to bind managed objects to real Threads.. it isnt that safe anymore to access a context on different threads - a context without any objects MIGHT be safe but its objects are not
I have been working with a few applications that deal with NSURLConnections. While researching best practices I have noticed a lot of examples online showing how to use NSOperation and NSOperationQueue to deal with this.
I have also noticed on stackoverflow a few examples that show initializing the connection as synchronous and asynchronous using the class methods of NSURLConnection: sendAsynchronousRequest and sendSynchronousRequest.
Currently I am doing my initialization as follows:
[[NSURLConnection alloc] initWithRequest:request delegate:self];
While doing this I have monitored the main thread and the calls to the delegate methods:
connectionDidFinishLoading, connectionDidReceiveResponse, connectionDidReceiveData and connectionDidFailWithError
Everything I have read in Apples documentation and my tests prove to me that this is asynchronous by default behavior.
I would like to know from more experienced Objective C programmers when the other options would be used for either a best practice, or just be more correct than what I see as the most simplistic way to get async behavior?
This is my first question I have posted on here, if more information is needed please ask.
Synchronous is bad bad bad. Try to avoid it. That will block up your main thread if the data transfer is large, thus resulting in an unresponsive UI.
Yes, it is possible to dispatch a synchronous call onto a different thread, but then you have to access any UI elements back on the main thread and it is a mess.
Normally I just use the delegate methods you have described - it is straightforward, and NSURLConnection already handles the asynchronous call for you away from the main thread. All you need to do is implement the simple delegate methods! It's a little more code, but you always want to go asynchronous. Always. And when it is finished loading, use the information you get to update the UI from the finishedLoading delegate method.
You also have the option of using blocks now, but I can't speak for how well those work or even how to use them well. I'm sure there's a tutorial somewhere - the delegate methods are just so easy to implement.
The method you list are the traditional means of asynchronous transfer and an app that uses them will be efficient in processor (and hence power) use.
The sendAsynchronousRequest method is a relatively new addition, arriving in iOS 5. In terms of best practice there's little other than style to differentiate between it and the data delegate methods other than that a request created with the latter can be cancelled and a request created with the former can't. However the tidiness and hence the readability and greater improbability of bugs of the block-based sendAsynchronousRequest arguably give it an edge if you know you're not going to want to cancel your connections.
As a matter of best practice, sendSynchronousRequest should always be avoided. If you use it on the main thread then you'll block the user interface. If you use it on any other thread or queue that you've created for a more general purpose then you'll block that. If you create a special queue or thread for it, or post it to an NSOperationQueue then you'll get no real advantages over a normal asynchronous post and your app will be less power efficient per Apple's standard WWDC comments.
References to sendSynchronousRequest are probably remnants of pre-iOS 5 patterns. Anywhere you see a sendSynchronousRequest, a sendAsynchronousRequest could be implemented just as easily and so as to perform more efficiently. I'd guess it was included originally because sometimes you're adapting code that needs to flow in a straight line and because there were no blocks and hence no 'essentially a straight line' way to implement an asynchronous call. I really can't think of any good reason to use it now.
I have written a Core Data abstraction class which holds the persistent store, object model and object context. To make the multithreading easier, I have written the accessor for the object context so that it returns a instance that is only available for the current thread by using [NSThread currentThread] to identify the threads.
This works perfectly as long as I don't use GCD, which I want to use as replacement for the old NSThread's. So my question is, how do I identify a GCD thread? The question applies for both iOS and Mac OS X but I guess that its the same for both platforms.
You could check whether dispatch_get_current_queue() returns anything. I like Jeremy's idea of transitioning to a CD-context-per-queue instead of CD-context-per-thread model using the queue's context storage though.
Perhaps you can store the CD context for each thread in the GCD context using dispatch_set_context()
The contextForCurrentThread helper method in Magical Record is very similar to what to said (i.e. keep one context per thread). The GCD execution block, while running on a single queue, can potentially run on any thread managed by GCD, which will cause some random crashes. Check this article: http://saulmora.com/2013/09/15/why-contextforcurrentthread-doesn-t-work-in-magicalrecord/