I have been working on a JSON parser for a little while https://github.com/nathanday/ndjson that parsers a stream of bytes instead of a complete document and convert directly into CoreData entities or custom objects instead of the usual property list objects. I am close to a version 1.0 but I have gotten to a point where to support NSURLConnection connection properly and to make parsing zipped JSON byte streams easier I have to change the way my parse internally works so that it can be called repeated (with the NSData objects the NSURLConnectionDelegate didReceiveData: method for example).
I have two choice that I can think of, the simplest is use a thread to wait on the next piece of data available, or alternately I can rewrite the parsing part of my code so that it can be repeatedly be called, picking up from where it last was by creating my own stake for the variables that need to be maintained between calls.
Using threads is simplest as it doesn't require very little rewriting if any, but as this is supposed to be a library for general use I am concerned about creating more threads than needed on a resources constrained device like the iPhone. Of cause the other options will make the code more complicated and having to maintain my own stack will not be resource free.
Does anybody have any good advice or maybe another possible options. Is creating threads expensive. Maybe someone can think of a creative way using block, or is it possible to call the NSRunLoop object to execute the next event (NSURLConnectionDelegate methods).
Under iOS and OS X, Apple provides a great way to do threads without headache: Grand Central Dispatch. Threads aren't expensive, and the system take care of creating the threads for you.
You can use serial queues to process your data and then sync it on the main thread using blocks:
// create the queue that will process your data:
dispatch_queue_t dataProcessQueue = dispatch_queue_create("data process queue", NULL); // the name is there for debugging purposes
//dispatch to the newly created queue, and do not wait for it to complete
dispatch_async(dataProcessQueue, ^{
//your asynchronous job
dispatch_async(dispatch_get_main_queue(), ^{
// the work that has to be done on your main thread using data from above
});
});
// don't forget to release the queue
dispatch_release(dataProcessQueue);
If you need to do concurrent work, you should use concurrent queues.
Apple's documentation is here
Related
As you may have experienced, access none-thread safe variables is a big headache. For iOS one simple solution is to use keyword #synchronized, which will add NSLock to insure the data can be accessed by unique one thread, the disadvantage is as below:
Lock too many will reduce app performance greatly, especially when invoked by main thread.
Dead lock will occur when logic becomes complex.
Based on the above considerations, we prefer to use serial queue to handle, each thread safe critical operation will append to the end of the queue, it is a great solution, but the problem is that all access interfaces should by designed in asyn style, see the following one.
-(id)objectForKey:(NSString *)key;
The people who invoke this class aren't reluctant to design in this way. Anyone who has experience on this field please share and discuss together.
The final solution is using NSUserDefault to store small data, for large cache data put them in file maintained by ourselves.
Per Apple doc the advantage of NSUserDefault is thread safe and will do synchronize work periodically.
This question already has answers here:
Use of the terms "queues", "multicore", and "threads" in Grand Central Dispatch
(3 answers)
Closed 8 years ago.
I am new to iOS development. Now I am quite confused about the two concepts: "thread" and "queue". All I know is that they both are about multithread programming. Can anyone interpret those two concepts and the difference between them for me?
Thanks in advance!
How NSOperationQueue and NSThread Works:
NSThread:
iOS developers have to write code for the work/process he want to perform along with for the creation and management of the threads themselves.
iOS developers have to be careful about a plan of action for using threads.
iOS developer have to manage posiable problems like reuseability of thread, lockings etc. by them self.
Thread will consume more memory too.
NSOperationQueue:
The NSOperation class is an abstract class which encapsulates the code and data associated with a single task.
Developer needs to use subclass or one of the system-defined subclasses of NSOperation to perform the task.
Add operations into NSOperationQueue to execute them.
The NSOperationQueue creates a new thread for each operation and runs them in the order they are added.
Operation queues handle all of the thread management, ensuring that operations are executed as quickly and efficiently as possible.
An operation queue executes operations either directly by running them on secondary threads or indirectly using GCD (Grand Central Dispatch).
It takes care of all of the memory management and greatly simplifies the process.
If you don’t want to use an operation queue, you can also execute an operation by calling its start method. It may make your code too complex.
How To Use NSThread And NSOperationQueue:
NSThread:
Though Operation queues is the preferred way to perform tasks concurrently, depending on application there may still be times when you need to create custom threads.
Threads are still a good way to implement code that must run in real time.
Use threads for specific tasks that cannot be implemented in any other way.
If you need more predictable behavior from code running in the background, threads may still offer a better alternative.
NSOperationQueue:
Use NSOperationQueue when you have more complex operations you want to run concurrently.
NSOperation allows for subclassing, dependencies, priorities, cancellation and a supports a number of other higher-level features.
NSOperation actually uses GCD under the hood so it is as multi-core, multi-thread capable as GCD.
Now you should aware about advantages and disadvantages of NSTread and NSOperation. You can use either of them as per needs of your application.
Before you read my answer you might want to consider reading this - Migrating away from Threads
I am keeping the discussion theoretical as your question does not have any code samples. Both these constructs are required for increasing app responsiveness & usability.
A message queue is a data structure for holding messages from the time they're sent until the time the receiver retrieves and acts on them. Generally queues are used as a way to 'connect' producers (of data) & consumers (of data).
A thread pool is a pool of threads that do some sort of processing. A thread pool will normally have some sort of thread-safe queue (refer message queue) attached to allow you to queue up jobs to be done. Here the queue would usually be termed 'task-queue'.
So in a way thread pool could exist at your producer end (generating data) or consumer end (processing the data). And the way to 'pass' that data would be through queues. Why the need for this "middleman" -
It decouples the systems. Producers do not know about consumers & vice versa.
The Consumers are not bombarded with data if there is a spike in Producer data. The queue length would increase but the consumers are safe.
Example:
In iOS the main thread, also called the UI thread, is very important because it is in charge of dispatching the events to the appropriate widget and this includes the drawing events, basically the UI that the user sees & interacts.
If you touch a button on screen, the UI thread dispatches the touch event to the app, which in turn sets its pressed state and posts an request to the event queue. The UI thread dequeues the request and notifies the widget to redraw itself.
I have a streaming iOS app that captures video to Wowza servers.
It's a beast, and it's really finicky.
I'm grabbing configuration settings from a php script that shoots out JSON.
Now that I've implemented that, I've run into some strange threading issues. My app connects to the host, says its streaming, but never actually sends packets.
Getting rid of the remote configuration NSURLConnection (which I've made sure is properly formatted) delegate fixes the problem. So I'm thinking either some data is getting misconstrued across threads or something like that.
What will help me is knowing:
Are NSURLConnection delegate methods called on the main thread?
Will nonatomic data be vulnerable in a delegate method?
When dealing with a complex threaded app, what are the best practices for grabbing data from the web?
Have you looked at AFNetworking?
http://www.raywenderlich.com/30445/afnetworking-crash-course
https://github.com/AFNetworking/AFNetworking
It's quite robust and helps immensely with the threading, and there are several good tutorials.
Are NSURLConnection delegate methods called on the main thread?
Yes, on request completion it gives a call back on the main thread if you started it on the main thread.
Will nonatomic data be vulnerable in a delegate method?
Generally collection values (like array) are vulnerable with multiple threads; the rest shouldn't create anything other than a race problem.
When dealing with a complex threaded app, what are the best practices for grabbing data from the web?
I feel it's better to use GCD for handling your threads, and asynchronous retrieval using NSURLConnection should be helpful. There are few network libraries available to do the boilerplate code for you, such as AFNetworking, and ASIHTTPRequest (although that is a bit old).
Are NSURLConnection delegate methods called on the main thread?
Delegate methods can be executed on a NSOperationQueue or a thread. If you not explicitly schedule the connection, it will use the thread where it receives the start message. This can be the main thread, but it can also any other secondary thread which shall also have a run loop.
You can set the thread (indirectly) with method
- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode
which sets the run loop which you retrieved from the current thread. A run loop is associated to a thread in a 1:1 relation. That is, in order to set a certain thread where the delegate methods shall be executed, you need to execute on this thread, retrieve the Run Loop from the current thread and send scheduleInRunLoop:forMode: to the connection.
Setting up a dedicated secondary thread requires, that this thread will have a Run Loop. Ensuring this is not always straight forward and requires a "hack".
Alternatively, you can use method
- (void)setDelegateQueue:(NSOperationQueue *)queue
in order to set the queue where the delegate methods will be executed. Which thread will be actually used for executing the delegates is then undetermined.
You must not use both methods - so schedule on a thread OR a queue. Please consult the documentation for more information.
Will nonatomic data be vulnerable in a delegate method?
You should always synchronize access to shared resources - even for integers. On certain multiprocessor systems it is not even guaranteed that accesses to a shared integer is safe. You will have to use memory barriers on both threads in order to guarantee that.
You might utilize serial queues (either NSOperationQueue or dispatch queue) to guarantee safe access to shared resources.
When dealing with a complex threaded app, what are the best practices for grabbing data from the web?
Utilize queues, as mentioned, then you don't have to deal with threads. "Grabbing data" is not only a threading problem ;)
If you prefer a more specific answer you would need to describe your problem in more detail.
To answer your first question: The delegate methods are called on the thread that started the asynchronous load operation for the associated NSURLConnection object.
I am confused on where to use which multithreading tool in iOS for hitting services and changing UI based on service data,
firstly I got accustomed to using NSURLConnection and its delegates, used didreceiveresponse, didreceivedata etc delegates to achieve the task
secondly I learned and used GCD to hit services and update the UI from within the block code
Now I am learning to use performSelectorInBackground() to do work in background thread
Clearly confused on which tool to use where?
NSURLConnection with delegate calls is "old school" way of receiving data from remote server. Also it's not really comfortable to use with few NSURLConnection instances in a single class (UIViewController or what not). Now it's better to use sendAsynchronousRequest.. method with completion handler. You can also define on which operation queue (main for UI, or other, background one) the completion handler will be run.
GCD is good for different tasks, not only fetching remote resources with initWithContentsOfURL: methods. You can also control what type of queues will receive your blocks (concurrent, serial ,etc.)
performSelectorInBackground: is also "old school" way of performing a method in background thread. If you weren't using ARC, you'd need to setup separate autorelease pool to avoid memory leaks. It also has a limitation of not allowing to accept arbitrary number of parameters to given selector. In this case it's recommended to use dispatch_async.
There are also NSOperationQueue with NSOperation and its subclasses (NSInvocationOperation & NSBlockOperation), where you can run tasks in the background as well as get notifications on main thread about finished tasks. IMHO They are more flexible than GCD in a way that you can create your own subclasses of operations as well as define dependencies between them.
The most important thing is, that you never change UI anyway in another thread except the main thread.
I think, that all points you mentioned use the same technique in the background: GDC. But I'm not sure of that.
Anyway it doesn't matter which tool you should use in terms of threading.
It's rather a question of your purpose. If you wan't to fetch an small image or just few data you can use contentsOfURLin a performSelectorInBackground() or a GDC dispatch block.
If it's about more data and more information like progress or error handling you should stick with *NSURLConnection`.
I suggest using GCD in all cases. Other techniques are still around but mainly for backward compatibility.
GCD is better for 3 reasons (at least):
It's extremely easy to use and the code remains very readable because of the use of blocks
It is lower level than things like NSOperation so it is much faster when you need high performance multi threading
It's lightweight and non-intrusive so your code doesn't have to change substantially when you want to add thread management in the middle of a method.
My app downloads several resources from server, data and data descriptors. These downloads, triggered by user actions, can be performed simultaneously, let's say, up to 50 downloads at a time. All these asynchronous tasks end up creating objects in memory, (e.g. appending leaves to data structures, such as adding keys to mutable dictionaries or objects to arrays). My question is: can this cause stability issues? For instance, if several simultaneous tasks try to add keys to the same dictionary, am I supposed to handle the situation, placing some kind of locks? If I implement a for cycle which looks for graphical elements in an array, is it possible that other running tasks might change the array content 'during' the cycle? Any reference or major, general orientation about this multitasking, multithreading issues other than official documentation?
Depends how you are dealing with the downloads - if you are using NSURLConnection it handles the separate threading / concurrency for you and your code is reentrant thus you don't have to worry about simultaneous action.
If you are creating your own threads you potentially have issues.
EDIT:
Your code runs in a main thread (the main run loop), lets say you have an NSURLConnection that is also running then it will run in a separate thread. However your delegate code that deals with events that happen while the connection is in progress runs in your run loop, not in the other thread. This means your code can only ever execute one thing at a time. A connection succeeded method would not get called at the same time as any of your other code. If you had a for loop running then it would block your main thread until it has finished looping, in the meanwhile if the connection finished while the for loop is still running then your delegate code will not execute until after the loop has finished.
You may want to look into Grand Central Dispatch's (GCD) and barrier blocks. Barrier blocks will allow you to do what y oh want in the background and "lock" resources.
Check out the Apple documentation and Mike Ash's blog post here on GCD.
The basic gist is that you use a concurrent queue that you create to perform the reads and use a barrier block to block all access to that resource for writing. good stuff.
Good luck
Tim