I have seen this code snippet:
dispatch_async(dispatch_get_main_queue(), ^{
[self doSomeNetworkStuff];
});
This doesn't look like making much sense to me.
EDIT: To clarify the conditions of my question:
The call to dispatch_async is performed from the main thread.
The sent message doSomeNetworkStuff is the heavy lifting worker task.
... and is not only the UI-updating task.
Dispatch, sure, but using the main queue would just pull the dispatched task back to the ui thread and block it.
Please, am I missing something?
Thanks.
dispatch_async lets your app run tasks on many queues, so you can increase performance.
But everything that interacts with the UI must be run on the main thread.
You can run other tasks that don't relate to the UI outside the main thread to increase performance.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//Add some method process in global queue - normal for data processing
dispatch_async(dispatch_get_main_queue(), ^(){
//Add method, task you want perform on mainQueue
//Control UIView, IBOutlet all here
});
//Add some method process in global queue - normal for data processing
});
Swift 3:
DispatchQueue.global(attributes: .qosBackground).async {
print("This is run on the background queue")
DispatchQueue.main.async {
print("This is run on the main queue, after the previous code in outer block")
}
}
when you want to do some Webservicecall or something you dispatch a async call like this below:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{
//Call your webservice here , your app will not freeze at all
});
Now, suppose you want to update or push a ViewController from your dispatched thread, if you directly push viewcontroller from this, app will or may get crashed,as such UI updates should be done in main thread of app,below is the answer for this then.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{
//Call your webservice here , your app will not freeze at all
//To update UIFrom dispatched Thread:
dispatch_async(dispatch_get_main_queue,^{
//Push view controller here
});
});
for detail visit : blackberrymastercracks.blogspot.in
It depends from where this code is being called. Means if its calling from main queue then it doesn't make sense. (Note: it will not cause a crash but it will just add a task in main queue ).
If this code is written in background thread then this is a converging point for the application. Like you are getting data from web service in background thread then wants to update it on UI then you can call it.
-(void) backgroundThreadFunction {
//Some stuff on background thread.
dispatch_async(dispatch_get_main_queue(), ^{
//Wants to update UI or perform any task on main thread.
[self doSomeNetworkStuff];
});
}
You can find more details over apple documentation https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html
or from this answer also https://stackoverflow.com/a/19822753/505735
Do post me if its still unclear. I will write a detailed answer.
You'll usually see that syntax inside of another dispatch_async call that runs on a background thread. This is because all updates to the UI should happen on the main thread, not in the background.
I lost track of this question, but as it still gets traction, I'll post an answer to this (using swift)
Assumptions: I do know that UI work has to be done on the main thread.
//
// We are on the main thread here.
// The following will schedule the closure on the main thread after ALL other
// routines currently scheduled on the main thread are done.
//
DispatchQueue.main.async {
//
// So here we are back on the main thread AFTER all routines on the main
// thread have completed.
//
// If the following call does NOT dispatch onto a background thread
// it will block the UI and it was really bad programming.
//
// Thus, for now and for the benefit of the doubt, let's assume
// `doSomeNetworkStuff()` DOES dispatch to a background thread.
//
// This can only make sense if the the func `doSomeNetworkStuff()`
// relies on results of code paths following this current
// `DispatchQueue.main.async(... we are here ...)`.
//
// If `doSomeNetworkStuff()` does NOT depend on any other code paths:
// Why not directly scheduling it directly on a background thread?
// Which is unnecessary, as as stated above it MUST dispatch on to the
// background anyways.
//
// Moreover, there is few possibility that `doSomeNetworkStuff()` does
// depend on other codepaths, because `self` is already captured by
// the closure.
//
self.doSomeNetworkStuff()
}
Taking all this together IMHO the original code does not make very much sense. It could be replaced with:
// We are on the main thread here
self.doSomeNetworkStuff()
The original async dispatch onto the main thread to then dispatch to background should be wasteful and confusing (obviously).
Unfortunately I am not in the position anymore to try this out with the original code base.
Am I missing an idea here?
Related
In Swift, I used this kind of pattern sometimes.
DispatchQueue.global().async {
// do stuff in background, concurrent thread
DispatchQueue.main.sync {
// update UI
}
}
The purpose of this pattern is clear. Do time consuming calculation in global thread so UI is not locked and update UI in main thread after calculation is done.
What if there's nothing to calculate? I just found a logic in my project which
//A
DispatchQueue.main.sync {
// do something
}
crashes but
// B
DispatchQueue.global().async {
DispatchQueue.main.sync {
// do something
}
}
doesn't crash.
How are they different? And Is case B different with just this?
// C
DispatchQueue.main.async {
// do something
}
And one more question. I know main thread is serial queue, but if I run multiple code block in multiple main.async, it works like concurrent queue.
DispatchQueue.main.async {
// do A
}
DispatchQueue.main.async {
// do B
}
If main thread is really a serial queue, how can they run simultaneously? If it is just a time slicing than how are they different with global concurrent queue other than main thread can update UI?
x.sync means that the calling queue will pause and wait until the sync block finishes to continue. so in your example:
DispatchQueue.global().async {
// yada yada something
DispatchQueue.main.sync {
// update UI
}
// this will happen only after 'update UI' has finished executing
}
Usually you don't need to sync back to main, async is probably good enough and safer to avoid deadlocks. Unless it is a special case where you need to wait until something finishes on main before continuing with your async task.
As for A example crashing - calling sync and targeting current queue is a deadlock (calling queue waits for the sync block to finish, but it does not start because target queue (same) is busy waiting for the sync call to finish) and thats probably why the crash.
As for scheduling multiple blocks on main queue with async: they won't be run in parallel - they will happen one after another.
Also don't assume that queue == thread. Scheduling multiple blocks onto the same queue, might create as many threads as system allow. Just the main queue is special that it utilises Main thread.
I am currently making an app which initiates a very long task on the viewDidLoad method. The nature of it is stopping the view from loading at all for extended periods of time and sometimes causes the app to crash. As such, I need to be able to process this particular task in the background so that the view can load instantly and then, in the background, complete the task and update the view when it is done. Does anybody know how to do this?
Try to use GCD similar to this:
let backgroundQueue = dispatch_get_global_queue(CLong(DISPATCH_QUEUE_PRIORITY_HIGH), 0)
dispatch_async(backgroundQueue) {
// Do your stuff on global queue.
dispatch_async(dispatch_get_main_queue(), { () -> Void in
// After finish update UI on main queue.
})
}
Or you can use NSOperationQueue. At WWDC 2105 was very nice talk about it. https://developer.apple.com/videos/wwdc/2015/?id=226
I've been using NSOperationQueue's addOperationWithBlock: to run code in background threads, like so:
self.fetchDataQueue = NSOperationQueue()
for panel in self.panels {
self.fetchDataQueue.addOperationWithBlock() {
() -> Void in
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
//Background code
}
}
}
I'm concerned that I may be doing this wrong. I can't see a way that the fetch queue would be able to know when an operation is done, since there's no completion to call, and I'm not confident it's tracking activity across threads to make sure it's still going.
And the point of using this is so that I don't queue them up in single file and take much longer to process, and so I don't run them all at once and use too much memory.
EDIT: I'm aware that I don't need to be doing dispatch_async, but it's simply an example of some block-based code I may call which may do the same thing, or a web request which may get back after a delay.
Well, your code will run in a background block. If you are using a queue to make sure that one operation only starts when the next one is finished, you may be in trouble: The block that you happen to the NSOperationQueue has finished as soon as it has dispatched the background code to GCD, not when the background code has actually finished which may be much later.
From Main UIViewController I call
if (required) [dataDB function];
next command;
....
....
in the Database UIViewController
- (void) Function {
Display Alert Message for Processing;
performs steps (takes some time)
....
....
Close Alert Message
}
Although one should NOT block code
I need the [dataDB Function] to complete before next command is called;
Yet I need the Alert to start showing before perform steps starts.
Currently Alert appears after [dataDB Function] completes and closes almost immediately.
Please help.
try this code
if (required)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[dataDB function];
dispatch_async(dispatch_get_main_queue(), ^{
next command;
});
});
}
it will create async task of [dataDB function];and after competition of it, it will perform task on main queue of next command;
You want to use some combination of GCD dispatch queues and the completion block pattern.
You should use dispatch_async() to queue db functions to complete serially on a background queue (a non-concurrent one, so that they are executed in the order you dispatch them). Then you can show your alert on the main thread while you wait for operations to complete on the background queue. You can use a completion block that you pass to one of the background operations to call back to the main thread on completion, or use the dispatch_group_notify() functionality.
You could also consider using an NSOperationQueue, but I find just dispatching blocks to be much easier.
I have an app that uses a connection queue that handles the connections on a background thread. Each connection sends a JSON post, then when it receives a success, saves some objects into coredata.
Once all connections are complete, i call a dispatch_async on the main thread to call a finished method.
However, under very specific conditions of data im sending/saving, I've noticed the dispatch_async block to the main thread never gets called, and the app screen freezes, all execution stops, and the app sits idle with a frozen screen. processing power according to xcode is 0%.
Here is method with the block that fails.
- (void)connectionDidComplete
{
_completeConnections++;
_syncProgress = (float)_completeConnections / (float)_totalConnections;
dispatch_async(mainQueue, ^(void) {
[[NSNotificationCenter defaultCenter] postNotificationName:SyncQueueDidUpdateNotification object:nil];
}); <-- this dispatch works
if (_completeConnections == _totalConnections)
{
// clear unsynced data
NSArray *syncedObjects = [SyncObject completedSyncObjects];
if (syncedObjects.count > 0)
{
for (SyncObject *syncObject in syncedObjects)
{
[syncObject delete];
}
}
//this method saves the current context, then merges this context with the main context right after
[[VS_CoreDataManager sharedManager] saveManagedObjectContextAndWait:managedObjectContext];
// cleanup the thread's context
[[VS_CoreDataManager sharedManager] unRegisterManagedObjectContextForThread:currentThread];
managedObjectContext = nil;
// complete sync
dispatch_async(mainQueue, ^(void) {
[self performSelector:#selector(finishSync) withObject:nil afterDelay:2];
}); <-- this dispatch never gets called
}
}
My suspicion is this problem has something to do with saving the context then merging it. And possibly while that is happening its released in the middle of the merge, causing some weird hang up and the dispatch isn't getting executed. This is just a guess though, and I don't know how to fix it.
Any ideas?
Thanks.
If the block on the main thread is not executed, then it is because of 1 of 2 reasons.
The main thread is blocked; is not processing any events at all. Got a while() loop on the main thread? That'd do it. A lock? There you go.
The main thread is running a modal run loop inside the outer run loop. Asynchronous dispatches to the main event loop -- main thread -- won't be processed in this case.
Set a breakpoint on that dispatch_async() and see what the main thread is doing (at the point of dispatch the main thread is most likely already in the bad state).
DarkDust's suggestion of using dispatch_after() is a good one, but is unlikely to work in that it is almost assuredly the case that your main thread is not processing events when the problem occurs. I.e. fix the problem, then move to dispatch_after() as DarkDust suggests.
If your main thread is busy with modal runloop, then you could try
CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, block
});
I believe this is a great discussion. I came across this when I had the following code:
dispatch_synch(dispatch_get_main_queue()){
print("I am here")
}
the print code did not execute as I was dispatching a 'synch' block on the serial main thread which caused a dead lock. print was waiting for the dispatch to finish and dispatch was waiting for print to finish. When you dispatch in the main serial queue then you should use dispatch_async. and i guess if you use a concurrent queue then dispatch synch suits better