What is the purpose of nesting dispatch_async(dispatch_get_main_queue()^{}) ? - ios

I've inherited some code that has this rather unusual nested sequence. The usual paradigm would have a single dispatch to the main queue to update the UI. The code, shown below, nests a dispatch to the main queue within another dispatch to the main queue.
- (void)viewDidLoad
{
// Setup some data
// Adjust UI
dispatch_async(myBackgroundQueue, ^{
while(Do_some_time_consuming_work) {
// Time consuming work goes here
if (things_are_going_slowly) {
dispatch_async(dispatch_get_main_queue(), ^{ // <- one of these two seems redundant
dispatch_async(dispatch_get_main_queue(), ^{ // <- one of these two seems redundant
stillWorkingLabel.hidden = NO; //Let user know the work is still ongoing
});
});
)
// Finish time-consuming work
}
});
}
What is the purpose, if any, of nesting dispatch_async(dispatch_get_main_queue()? This nested sequence shows up in several places in the app. It seems to me that only one dispatch to the main queue is needed.
I think I've read all of the relevant questions on related topics here and via Google search, but I haven't found anyone suggesting nesting two identical dispatches.
The app works well, with the UI updating as expected in the above example and in other places in the code.
Most of the app's code uses the usual non-nested version of the above scheme, and of course it also works just fine.
I'm inclined to just replace these nested calls with a single dispatch, but maybe I'm missing something here. Any advice would be appreciated.

I can't think of a single advantage to doing this, and can think of reasons not to. It will delay the execution of the inner closure, as well as taking a small amount of additional resources. (It's going to force the app to go through at least 2 passes through the event loop before the work item gets executed.)
I think removing the nested calls is the right thing to do.

Nesting two dispatch_queues for the main doesn't make any sense , the straight forward way is that
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// perform long task here
dispatch_async(dispatch_get_main_queue(), ^(){
//Add method, task you want perform on mainQueue
//Control UIView, IBOutlet all here
}); });

Related

Is there something bad will happend when construct multi level dispatchQueue

Snippet 1
let workerQueue = DispatchQueue(label: "foo")
workderQueue.async {
#code
DispatchQueue.main.async {
#code
workerQueue.async {
#code
}
}
}
Snippet 2
let workerQueue = DispatchQueue(label: "foo")
DispatchQueue.main.async {
#code
workerQueue.async {
#code
DispatchQueue.main.async {
#code
}
}
}
Is it ok to write code like snippet 1 or snippet 2 ? Will the main thread be blocked?
No, there’s nothing inherently “bad” with these patterns.
That having been said, the typical pattern is:
workerQueue.async {
// do something computationally intensive
DispatchQueue.main.async {
// update UI and/or model
}
}
And this is motivated by “I have something sufficiently intensive that I don’t want it running on the main queue (and adversely affecting the UX), but when I’m done, I need to update my UI and/or the model.”
It’s pretty rare that you also have a further level of nesting that says “and when I’m done updating the UI, I need to dispatch something else back to my same worker queue”, as shown in your first example. If you have a practical example of that, perhaps you can share it with us, as there might be more elegant ways of refactoring that to avoid a “tower” of nested dispatches, which can start to render the code a little hard to follow.
In your second example, where you’re dispatching to the main thread first is also a bit atypical. (Yes, we occasionally have to do that, but it’s less common.) I guess you’re presuming you’re already on some other thread (though not always). If that’s the case, where the code is expecting you to be on a particular thread, you might want to make that assumption explicit, e.g.:
func foo() {
dispatchPrecondition(condition: .onQueue(workerQueue))
// do some stuff that should be on the `workerQueue`
DispatchQueue.main.async {
// update UI, etc.
...
}
}
Bottom line, there’s absolutely no problem with an arbitrary level of nesting, especially if doing it with async ... doing this with sync can invite deadlock problems if you’re not careful. But from a practical “can future programmers read this code and clearly deduce what the resulting behavior is going to be”, you will often want to constrain this so it’s not too confusing.
As a practical example I might be doing something on some dedicate functional queue (e.g. a database access queue or an image processing queue), and I might need to use another synchronization queue to ensure thread-safe access, and I might need to do UI updates on the main queue. But I don’t generally have this tower of three levels of queues, but, for example, I encapsulate these various levels to avoid confusion (e.g. I have a reader-writer generic that encapsulates the details of that concurrent queue I use for thread-safe access), and my code avoids complicated intermingling different types of dispatch queues in any given method. At any particular level of abstraction I’m trying to avoid too many different queue types at one time.
You only need to execute code on desired thread, if you are on some another thread.
For example, Since by default app runs on main thread. But if a task runs on Background thread and modifies UI element within itself, then it should be enclosed in main thread.
some_background/other_thread_task {
DispatchQueue.main.async {
//UI Update
self.myTableView.reloadData()
}
}
Both your snippets are the same structure. That structure is totally normal and is exactly how to switch threads.

Swift handle lots of complex operations

I'm working on a Swift project with complicated notification calculations. I'm looping through an array of objects which I need to do a very complex operation to determine when to schedule notifications. Currently I am doing:
for item in items {
//some logic here
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
//complex operation here, then schedule notification
}
}
Unfortunately this is proving to be slow since I am doing this for a bunch of objects that are all trying to use the same queue. Sometimes it doesn't finish scheduling the notifications before the user leaves the app. What are my options to improve the performance? I was thinking instead of having everything use the global high priority queue I could create new queues each time somehow so they are not waiting on each other?
First, I don't think you need to use the "main thread" for calculation, the main thread is mainly for UI updates. You should use background thread to handle those heavy operations and schedule notifications. Otherwise you app is going to be very laggy and not responsive(as you main thread is occupied by those operations)
Second, in stead of firing multiple main thread operations using a for loop. You should put the code in this way.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
for item in items {
//some logic here
//complex operation here, then schedule notification
}
}
As you didnt provide code of the complex operation, can't give any advise on that part. Feel free to add follow up questions. :D

iOS: Background Threads / Multithreading?

If a second method is called from a method that is running on a background thread, is the second method automatically ran in that same thread or does it happen back on the main thread?
Note: I want my second method to be handled in the background, but since I update the UI inside it, would doing the following, be the right way to do it:
- (void)firstMethod {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
//Do stuff in background
...
//Call a second method (Assume it'll run in this background thread as well)
[self secondMethod];
});
}
//Second Method
- (void)secondMethod {
//Do heavy lifting here
...
dispatch_async(dispatch_get_main_queue(), ^{
//Update UI here
...
});
}
Update
Oh I totally forgot to mention that this method is something that loads suggestions into the view (think keyboard suggestions). Since every key tap would be calling this method, I only want it to run when a user has finished typing. The way I'm approaching it is by setting a 0.2 delay between keys and if a new key tap fall within that 0.2 delay it cancels the previous method call, and initiates a new call (this way, assuming the use types the word, "the", it doesn't run suggestions for "t", "th", "the". Since the user is typing pretty quickly we can assume they don't want suggestions for anything until they have stopped typing (allowing the call to go through after a 0.2s delay), or if they type slow (where they probably are looking for suggestions along the way).
So when calling my secondMethod I do the following:
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(secondMethod) object:nil];
[self performSelector:#selector(secondMethod) withObject:nil afterDelay:0.2];
The problem is it's not being called (I'm assuming this method defaults it to be performed in the main thread?)
Generally speaking, nothing is going to hop between threads without being pretty explicit about it. Certainly something as trivial as just calling a method isn't. Your code seems fine. Remember to not access mutable state from more than one queue at once (for example if the heavy lifting uses instance variables, make sure that -firstMethod doesn't get called twice in a row. It'd spawn off two async calls to -secondMethod then, and they'd step all over each others data. If that's a problem, create a serial dispatch queue instead of using a global one).

#synchronized block versus GCD dispatch_async()

Essentially, I have a set of data in an NSDictionary, but for convenience I'm setting up some NSArrays with the data sorted and filtered in a few different ways. The data will be coming in via different threads (blocks), and I want to make sure there is only one block at a time modifying my data store.
I went through the trouble of setting up a dispatch queue this afternoon, and then randomly stumbled onto a post about #synchronized that made it seem like pretty much exactly what I want to be doing.
So what I have right now is...
// a property on my object
#property (assign) dispatch_queue_t matchSortingQueue;
// in my object init
_sortingQueue = dispatch_queue_create("com.asdf.matchSortingQueue", NULL);
// then later...
- (void)sortArrayIntoLocalStore:(NSArray*)matches
{
dispatch_async(_sortingQueue, ^{
// do stuff...
});
}
And my question is, could I just replace all of this with the following?
- (void)sortArrayIntoLocalStore:(NSArray*)matches
{
#synchronized (self) {
// do stuff...
};
}
...And what's the difference between the two anyway? What should I be considering?
Although the functional difference might not matter much to you, it's what you'd expect: if you #synchronize then the thread you're on is blocked until it can get exclusive execution. If you dispatch to a serial dispatch queue asynchronously then the calling thread can get on with other things and whatever it is you're actually doing will always occur on the same, known queue.
So they're equivalent for ensuring that a third resource is used from only one queue at a time.
Dispatching could be a better idea if, say, you had a resource that is accessed by the user interface from the main queue and you wanted to mutate it. Then your user interface code doesn't need explicitly to #synchronize, hiding the complexity of your threading scheme within the object quite naturally. Dispatching will also be a better idea if you've got a central actor that can trigger several of these changes on other different actors; that'll allow them to operate concurrently.
Synchronising is more compact and a lot easier to step debug. If what you're doing tends to be two or three lines and you'd need to dispatch it synchronously anyway then it feels like going to the effort of creating a queue isn't worth it — especially when you consider the implicit costs of creating a block and moving it over onto the heap.
In the second case you would block the calling thread until "do stuff" was done. Using queues and dispatch_async you will not block the calling thread. This would be particularly important if you call sortArrayIntoLocalStore from the UI thread.

Recommended Design Patterns for Asynchronous Blocks?

I am working on an iOS app that has a highly asynchronous design. There are circumstances where a single, conceptual "operation" may queue many child blocks that will be both executed asynchronously and receive their responses (calls to remote server) asynchronously. Any one of these child blocks could finish execution in an error state. Should an error occur in any child block, any other child blocks should be cancelled, the error state should be percolated up to the parent, and the parent's error-handling block should be executed.
I am wondering what design patterns and other tips that might be recommended for working within an environment like this?
I am aware of GCD's dispatch_group_async and dispatch_group_wait capabilities. It may be a flaw in this app's design, but I have not had good luck with dispatch_group_async because the group does not seem to be "sticky" to child blocks.
Thanks in advance!
There is a WWDC video (2012) that will probably help you out. It uses a custom NSOperationQueue and places the asynchronous blocks inside NSOperationsso you can keep a handle on the blocks and cancel remaining queued blocks.
An idea would be to have the error handling of the child blocks to call a method on the main thread in the class that handles the NSOperationQueue. The class could then cancel the rest appropriately. This way the child block only need to know about their own thread and the main thread. Here is a link to the video
https://developer.apple.com/videos/wwdc/2012/
The video is called "Building Concurrent User Interfaces on iOS". The relevant part is mainly in the second half, but you'll probably want to watch the whole thing as it puts it in context nicely.
EDIT:
If possible, I'd recommend handling the response in an embedded block, which wraps it nicely together, which is what I think you're after..
//Define an NSBlockOperation, and get weak reference to it
NSBlockOperation *blockOp = [[NSBlockOperation alloc]init];
__weak NSBlockOperation *weakBlockOp = blockOp;
//Define the block and add to the NSOperationQueue, when the view controller is popped
//we can call -[NSOperationQueue cancelAllOperations] which will cancel all pending threaded ops
[blockOp addExecutionBlock: ^{
//Once a block is executing, will need to put manual checks to see if cancel flag has been set otherwise
//the operation will not be cancelled. The check is rather pointless in this example, but if the
//block contained multiple lines of long running code it would make sense to do this at safe points
if (![weakBlockOp isCancelled]) {
//substitute code in here, possibly use *synchronous* NSURLConnection to get
//what you need. This code will block the thread until the server response
//completes. Hence not executing the following block and keeping it on the
//queue.
__block NSData *temp;
response = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]];
[operationQueue addOperationWithBlock:^{
if (error) {
dispatch_async(dispatch_get_main_queue(), ^{
//Call selector on main thread to handle canceling
//Main thread can then use handle on NSOperationQueue
//to cancel the rest of the blocks
});
else {
//Continue executing relevant code....
}
}];
}
}];
[operationQueue addOperation:blockOp];
One pattern that I have come across since posting this question was using a semaphore to change what would be an asynchronous operation into a synchronous operation. This has been pretty useful. This blog post covers the concept in greater detail.
http://www.g8production.com/post/76942348764/wait-for-blocks-execution-using-a-dispatch-semaphore
There are many ways to achieve async behavior in cocoa.
GCD, NSOperationQueue, performSelectorAfterDelay, creating your own threads. There are appropriate times to use these mechanisms. Too long to discuss here, but something you mentioned in your post needs addressing.
Should an error occur in any child block, any other child blocks should be cancelled, the error state should be percolated up to the parent, and the parent's error-handling block should be executed.
Blocks cant throw errors up the stack. Period.

Resources