Because I am a programmer from Android to iOS. I am quite familiar with Handler Looper MessageQueue etc. in Android. But I am a little confused with iOS when I find a code block [NSURLConnection start] called in main thread. Luckily I read NSDefaultRunLoopMode vs NSRunLoopCommonModes and Does NSURLConnection block the main thread?. I learned network communication can go on in main thread for iOS with the help of modes concept.
Now I have a another question. As we know UITracking mode have a high priority, but if the current moment is doing network job in default mode, then UI event happens and network job is not finished, the corresponding code or method execution is not over, how the execution state be processed, saved and restored for OS and how the modes switch well?
And using NSURLConnection asynchronously actually does create another thread, an internal one or not ?
Thanks!
Related
As we know, dart is a single-threaded language. So according to the document, we can use Futrure/Stream to implement a async opetation. It sends the time-consuming operation to the Event Queue.
What confused me is where the Event Queue working on. It is working on the dart threat? if yes, it will block the app.
Another question is Event Queue a FIFO queue. If i have two opertion, one is a 1mins needed networking request, the other is a click event. The two operation will send to the Event Queue.
So if the click event will blocked by the networking request? Because the queue is a FIFO queue?
So where is the event queue working on?
Thank you very much!
One thing to note is that asynchronous and multithreading are two different things. Dart uses Futures and async/await to achieve asynchronicity, but Dart is still inherently a single-threaded language.
The way it works is when a Future is created (either manually or via calling an async method), that process is added to an event queue, as you read. Then, in the middle of all the synchronous execution, whenever there is a lull, the event queue can take priority. It can then go through the processes and figure out if any of the Futures have been completed. If so, the result is passed along to any other asynchronous processes that are waiting on that resource, if any.
This also means that, yes, if your program hangs in the middle of an asynchronous operation (with the easy example of an endless loop via while (true) {}), it will freeze the entire program, including the synchronous code and other asynchronous processes still waiting to resolve (even if the conditions allowing them to resolve have already occurred).
However, in your case, this won't be an issue. If you fire an asynchronous process in the form of a network request followed by another in the form of a "click event" (not sure what you're referring to, but I'll assume it's asynchronous as well), they will both be added to the event queue in that order. But if the click event resolves before the network request, the event queue will merely recognize that the network request Future has not yet resolved and will move on to the click event that has.
As a side note, it's worth noting that Dart does have a multi-threading capability, albeit in a fairly roundabout way. Dart has something called an Isolate, which isn't a thread but a completely separate child program. This means that the Isolate cannot access any of the same data in memory as the root program itself. However, data can be passed between the two using SendPorts and ReceivePorts. This makes using Isolates slightly more complicated than threads, but it also means that, if no memory is shared, it virtually eliminates race conditions based on which thread accesses the memory first.
When using NSURLConnection, you had the option to schedule the connection using NSRunLoop:
- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode
Passing NSDefaultRunLoopMode would effectively cause the connection to pause if the user scrolled, which was great for performance as the user experience was never impacted by the download.
Is there a way to get similar behaviour for NSURLSession? I have read through the docs and tried various ways of configuring the session with no success.
NSURLSession works at an "upper" level, and is made to be more simple for the developer than using NSURLConnection.
I made some tests and I think that there is no possibility to control the runloop and the mode of NSURLSession, because they seems to be managed by an external daemon and not by your App (I tested only with NSURLSessionDownloadTask).
Do this simple test:
download and execute this Github project
start a download
open the "downloads" controller to see the state of your download
pause the app
wait a moment
unpause the app
you will see that the download has been continued while your app was paused, so when you start a NSURLSession the control is passed to the system, outside your app: it means that the main part of the work doesn't take place in an internal runLoop.
The only thing you have control on, is the serial queue on which the delegate calls are dispatched (passed back to your application). The delegate calls are queued for execution (on the main or on a background thread, you can choose it), since NSOperationQueue use Grand Central Dispatch to queue the calls, I'm not sure about the runloop mode used for this, but I think this is a good starting point to continue your researches.
EDIT:
If I remember correctly, dispatch calls made on background threads are made on threads where a runloop is not running. In fact, if you add this line
NSLog(#"%#", [[NSRunLoop currentRunLoop] currentMode]);
on one of the delegate methods of the FLDownloader class in the previous project, you will see that there is no run mode (nil), this happens when the runloop is not running.
If anyone ever runs into this problem again. You can't schedule the download task into a different run loop but you can handle the response in a different run loop mode which still greatly improves the performance while scrolling.
[self performSelectorOnMainThread:#selector(requestDidFinishLoadingWithData:)
withObject:data
waitUntilDone:YES
modes:#[NSDefaultRunLoopMode]];
I am trying to understand multi-threading on iOS in more detail. I went through some of the class references like NSThread, NSRunLoop, NSTask..
First of all as indicated on the following link:
use of runloop
Runloop runs within a Thread.
So why do we need to define our own Runloop in our app? In the case of NSThread it is useful because some of time-consuming processes can run in a separate thread so that the app will still be responsive on the main thread.
Interacting with the thread's run loop may be useful if you have a thread whose work you want to continue periodically. That is, a run loop would do some work, and then when it is finished with that work, it would put the thread to rest for some time, then resume work at a later time -- effectively preventing the thread from exiting. You won't need to interact with them or configure/create them yourself regularly (only a small percentage of apps would qualify, if you are using high level abstractions such as Foundation because Foundation would set them up on your behalf in most scenarios).
If your secondary thread just does a specified task and does not need to wait for some external event (e.g. a download to finish), you would (typically) not need to interact with the run loop.
You might consider looking at using NSOperationQueues, NSOperations and NSBlockOperations instead as these will manage themselves, will allow for cancellation of tasks and can be scheduled on main and background threads.
beside heavy processing, should multithreading mainly be used when you have a not quite responsive UI? or does it have other considerations?
How can I know if my application should have multithreading or not?
One of the Important Application of thread in ios is during network communication.Whole your app is communication with server and if you want to show busy view on UR UI you need to create thread in such scenario to perform network communication in background thread.
In IOS 5,You can opt for GCD(Grand Central Dispatch)Instead of thread to perform same functionality..
Basically in iOS development Threads are used when you don't want to affect you UI by a process which will take long time to complete. for example when you make a connection to parse xml,json,image data etc then you don't want to stop user interaction at that time you can use threads.
you can start a thread by using NSThread.
Things to have in mind before using threads -
You should never do a graphical change in a thread. If you need to
that in a thread then you can do only on main thread.
Never use a NSTimer in a secondary thread, because your thread may
complete before timer execution so timer may not run.
whenever you want to perform a long process then you can use thread.
The use of threading in ios is to ensure hussle-free and seamless experience by the end-users.
You can implement thread whenever you want to extract some resource over the network such as parsing or data retrieval and you don't want the ui to be affected as application would run on main thread and the web-operation on your custom thread.
You may want to use the thread when you need to have concurrent operations or simultaneous such as in game when you hae to have multiple animations on same object at same time.There can be quite a large number of scenarios which may need threading.
You may read Concurrency Programming Guide By Apple
and Thread Management
but threads may be an overhead in the application as it needs memory allocation and large operations on thread may affect the performance so use it when it can't be avoided.
You can use NSThread,NSOperations to create threads .GCD is deprecated now.
I am working on an app, which uploads native contacts to server then get responses(JSON, a contact list that already installed the app). When native contacts are large enough, server response will be slow and unstable. And user cannot do other things. so I put network request into background thread. every time I will upload 100 contacts, do some tasks , then next 100 contacts until loop finish.
But in running, the result is not as expected. background thread is running, it keeps to request server. UI thread is blocked, I still cannot do anything.
is this cause a long loop in background thread? Although I have 2 thread, but they will compete CPU resources(test device is iPod, 1 core. And I think this may not related core numbers)?
Could anyone tell me hints on how to handle this kind of scenario? Thanks in advance!
Update:
I have found the root cause. A global variable in App delegate is set to wrong value, therefore UI behavior is weird. I found this by comment all network request method. So this problem is not related with multiple threading. Sorry for the bother.
I think there needs to be some clarification as to how you are performing the network operations.
1st, NSOperatiomQueue deals with NSOperations, so you are presumably wrapping your network code in an NSOperation subclass.
2nd, are you using NSURLConnections for your networking code?
3rd, is the blocking part the NSURLConnection or you delegate callback for NSURLConnection?
1 thing to note is that plain ol' NSURLConnections are implemented under the hood multithreaded. The object is placed into your main threads run loop by default (when run from the main thread), but the object is just a wrapper that handles callbacks to the delegate from the lower level networking code (BSD sockets) which happens on another thread.
You really shouldn't be able to block your UI with NSURLConnections on the main thread, unless A) you are blocking the thread with expensive code in the delegate callback methods or B) you are overwhelming your run loop with too many simultaneous URL connections (which is where NSOperationQueue's setMaxConcurrentOperationsCount: comes into play)