Dispatching to main queue when I'm already in main thread [closed] - ios

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
Tell me if this make sense. This is an iOS question.
I'm seeing code where it is already in the main thread, but the code would dispatch_async all sorts of UI code to the main thread's queue. Layouts, animations etc etc.
I was told this some how speeds up responsiveness (example, when pushing a view controller, you would dispatch other UI ops there so it won't block the push transition.
This doesn't make sense because first it is dangerous, second, it doesn't guarantee when the UI code gets run(even though it will probably run with milliseconds). The only good reason I can see is for it to guarantee that the UI code is not accidentally run in a different thread.
What do you guys think?

There are definitely times you employ this pattern of dispatching back to the main queue, so I might not be too quick to dismiss it or label it as "dangerous" (though the way you characterize it, it does sound suspicious). You should share some code samples of how you're seeing this pattern being used, and we can comment further.
When would you dispatch to the main queue? The prototypical example is when you're doing something on a background queue, but then want to dispatch the UI updates back to the main queue, e.g.:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// do something time consuming here, like network request or the like
// when done, update the UI on the main queue:
dispatch_async(dispatch_get_main_queue(), ^{
// update the UI here
});
});
But I'm assuming this is not the sort of dispatch to the main queue you're talking about. I'm assuming from your comment where you have something on the main queue dispatching asynchronously right back to the main queue itself.
The reason you would do that is if you don't want the dispatched code to run immediately, but rather to be queued for the next iteration of the run loop. This lets the autorelease pool drain, lets the current method complete (and release any resources it might have been using), lets other dispatched tasks run first, gives the UI a chance to reflect any changes you may have initiated, etc.
A few examples of when some developers might do this include:
You might use this pattern if you want a method call itself recursively, but you want to yield back to the run loop, to let resources be freed, let the UI reflect any changes, etc. You're basically saying "ok, let this method finish, but in the next run loop, run this method again."
A little more suspect, I've seen this pattern in viewDidLoad where you want to give auto layout a chance to "catch up" and update the frames. E.g. there is a common third-party progress indicator that won't work if you just invoke it from viewDidLoad, but it works if you dispatch that update back to the main queue.
Having articulated reasons why I've seen developers dispatch back to the main queue from the main queue, itself, I must confess that many of these patterns suffer from code smell and are often better accomplished via different patterns. But these are a few examples that I've seen.
But, again, if you want assistance on your particular code sample, you have to share it with us. We can't tell what the developer intended without seeing the code sample.

Related

Why is it the programmer’s responsibility to call things on the main thread?

Why is it the responsibility of the programmer to call UI related methods on the main thread with:
DispatchQueue.main.async {}
Theoretically, couldn’t this be left up to the compiler or some other agent to determine?
The actual answer is developer inertia and grandfathering.
The Cocoa UI API is huge—nay, gigantic. It has also been in continuous development since the 1990's.
Back when I was a youth and there were no multi-core, 64-bit, anything, 99.999% of all applications ran on the main thread. Period. (The original Mac OS, pre-OS X, didn't even have threads.)
Later, a few specialized tasks could be run on background threads, but largely apps still ran on the main thread.
Fast forward to today where it's trivial to dispatch thousands of tasks for background execution and CPUs can run 30 or more current threads, it's easy to say "hey, why doesn't the compiler/API/OS handle this main-thread thing for me?" But what's nigh on impossible is re-engineering four decades of Cocoa code and apps to make that work.
There are—I'm going to say—hundreds of millions of lines of code that all assume UI calls are executing concurrently on the main thread. As others have pointed out, there is no cleaver switch or pre-processor that's going to undo all of those assumptions, fix all of those potential deadlocks, etc.
(Heck, if the compiler could figure this kind of stuff out we wouldn't even have to write multi-threaded code; you'd just let the compiler slice up your code so it runs concurrently.)
Finally, such a change just isn't worth the effort. I do Cocoa development full time and the number of times I have to deal with the "update control from a background thread problem" occurs, at most, once a week or so. There's no development cost-benefit analysis that's going to dedicate a million man-hours to solving a problem that already has a straight forward solution.
Now if you were developing a new, modern, UI API from scratch, you'd simply make the entire UI framework thread safe and whole question goes away. And maybe Apple has a brand new, redesigned-from-the-ground-up, UI framework in a lab somewhere that does that. But that's the only way I see something like this happening.
You would be substituting one kind of frustration for another.
Suppose that all UI-related methods that require invocation on the main thread did so by:
using DispatchQueue.main.async: You would be hiding asynchronous behaviour, with no obvious way to "follow up" on the result. Code like this would now fail:
label.text = "new value"
assert(label.text == "new value")
You would have thought that the property text just harmlessly assigned some value. In fact, it enqueued a work item to asynchronously execute on the main thread. In doing so, you've broken the expectation that your system has reached its desired state by the time you've completed that line.
using DispatchQueue.main.sync: You would be hiding a potential for deadlock. Synchronous code on the main queue can be very dangerous, because it's easy to unintentionally block (on the main thread) yourself waiting for such work, causing deadlock.
I think one way this could have been achieved is by having a hidden thread dedicated to UI. All UI-related APIs would switch to that thread to do their work. Though I don't know how expensive that would be (each switch to that thread is probably no faster than waiting on a lock), and I could imagine there's lots of "fun" ways that'll get you to write deadlocking code.
Only on rare instances would the UI call anything in the main thread, except for user login timeouts for security. Most UI related methods for any particular window are called within the thread that was started when the window was initialized.
I would rather manage my UI calls instead of the compiler because as a developer, I want control and do not want to rely on third party 'black boxes'.
check https://developer.apple.com/documentation/code_diagnostics/main_thread_checker
and UPDATE UI FROM MAIN THREAD ONLY!!!

iOS application have multiple main thread [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
Can we create multiple main thread in single application?
Why all UI changes made in main thread?
I have faced these question in interviews. I am unable to find any solution. Can any one help me to find the answers of this question? That will help me in future interviews and implementations in iOS app.
Thanks in advance!
There is only ever one main thread in your application, however tasks from multiple dispatch queues may execute on this thread. Tasks that are dispatched on the main queue are guaranteed to run on the main thread.
Generally with GCD you do not think about threads, but rather queues which are abstracted from the underlying threads. They provide a level of abstraction that makes it easier to manage tasks without being concerned about the number or state of the threads that are being used.
THe autolayout engine performs a number of calculations and applies rules in order to arrive at a layout solution. If the properties of a UI element change then the autolayout solution is invalidated and needs to be recalculated.
As the main queue is a serial dispatch queue, dispatching UI updates onto the main queue ensures that either the autolayout calculations are being performed or a UI property is being updated but not both at the same time (of course there are more than just these two activities happening on the main queue, but we are just addressing autolayout here)
No, there is only one main thread for the application that is created by system for application. Main thread is the thread that directly gives changes to user. Thread which is directly connect with user you can said.
Check the Apple Documentation, It states,
The main queue is automatically created by the system and associated with your application’s main thread. Your application uses one (and only one) of the following three approaches to invoke blocks submitted to the main queue:
Calling dispatch_main
Calling UIApplicationMain (iOS) or NSApplicationMain (OS X)
Using a CFRunLoopRef on the main thread
As with the global concurrent queues, calls to dispatch_suspend,
dispatch_resume, dispatch_set_context, and the like have no effect
when used with queues returned by this function.
Now, let's take an example, If you are downloading an image and want to display it to user. Now if you will download it on main thread then it will block other UI till it completed download. So, you should not download it on main thread or synchronously . you should download it asynchronously and when download is completed, you should display it to user on main thread, so it will quick displayed to user after download is completed.

Why are UI events not thread-safe in Swift/Objective-C?

So I'm beginning to learn the basics of Grand Central Dispatch and the whole concept of multithreading with iOS applications. Every tutorial will tell you that you must run UI events on the main thread, but I don't completely understand why.
Here's a problem I came across yesterday, and finally fixed it by running a segue on the main thread, but I still don't understand why running it off the main thread was a problem:
I had a custom initial VC (barcode scanner) and a segue to a new view controller with a UIWebView attached. As soon as the VC found a barcode, it called a handler, and in that closure, I had a performSegueWithIdentifier. However, I got a EXC_BAD_ACCESS because of this (it didn't happen when the second VC had a label or a UIImageView, just with UIWebView). I finally realized that for some reason, the closure was called off the main thread, and thus the segue was being performed off the main thread. Why exactly would performing the segue on another thread throw a memory error? Is it because self in self.performSegueWithIdentifier was somehow nil? And why wouldn't Swift automatically dispatch a segue event on the main thread?
Interesting question! The crash isn't related to UIKit. It's a crash specific to UIWebView. Looking at the stack trace, the exception happens in the WebCore::FloatingPointEnvironment::saveMainThreadEnvironment function, which is part of the WebKit init process. Since WebKit manages a threaded execution environment of its own, it makes sense that it needs a definite starting point (i.e. the main thread) to build this environment.
UIKit operations (like presenting a view controller) performed on threads other than main will not cause an exception, but they will be delayed (depending on the QoS of the dispatching queue).
As for why the UIKit operations aren't automatically dispatched on the main queue, I can only speculate that adding extra checks inside the library calls would add too much redundant work that can be avoided simply by following a convention.
For a larger discussion on UIKit and the main thread, see this answer: Why must UIKit operations be performed on the main thread?
The short answer is that all operations that modify the UI of your app need to come together in one place to be evaluated to generate the next frame at regular intervals (the V-Sync interval specifically). Keeping track of all of the mutated state requires all changes to happen synchronously, and for performance reasons, all of these operations are generally batched up and executed once per frame (while also coordinating with the GPU).
Making things thread-safe is difficult, and has major performance implications, all of which can be avoided by requiring access to come from a single (main) thread. You want your UI frameworks to be as fast (i.e. responsive) as possible. If you declare that all your UI objects are main-thread only, then you don't have to slow them down with a bunch of synchronization overhead. I've heard it asked, 'if UIKit is really main-thread only, then why don't they just check the current thread and abort() if it's not the main thread?' and the answer is the same: Even a simple check like that would result in an appreciable performance hit given the number of methods that would need the check and the frequency with which they're called. It's all about speed.
Also, remember, not too long ago, all applications were single threaded.

Slow application [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
is it possible to call an action that contain heavy operations several times? like save button (I save the first object) and want to add others, but the app becomes so slow and I can't navigate to other views
You can always play around with heavy data saving related tasks in the background. You can distribute the content related stuff to various threads (queues), you need to separate the stuff which you are saving and if it is blocking your UI and making your app slow then you need to perform these heavy operations in the background.
Make sure, you do NOT perform any UI updation operation in the background. Try reading about GCD (how it works), how you can create a background Queue etc and how you can play around with it. I assume you might be using core data in order to save the contents on save button. Try reading about the Parent/Child Manage Context Objects. Play around with it a bit and move your heavy task to background, updation of UI will always be on Main or UI thread (which you can always do it by calling get_main_queue() if you are working with dispatch queues). Happy Coding. If you have specific code, which is doing this, then let us know. We will be glad to help. :)
You need to make sure that you aren't tying up the main UI thread of your application. A potential easy fix is to do your save operation on a different thread. Here is an example of how to do just that using Grand Central Dispatch: iPhone - Grand Central Dispatch main thread
Example:
//notice this saveQueue is a new dispatch queue that's been created.
dispatch_queue_t saveQueue = dispatch_queue_create("com.mycompany.myqueue", 0);
dispatch_async(saveQueue, ^{
//this command represents your long running operation
doSaveOperation();
dispatch_async(dispatch_get_main_queue(), ^{
//always update your UI on the main thread!
[self showCompleteMessage];
});
});

Are all methods in an iOS app usually in a single thread? (for race condition prevention)

We can have many handlers: touches handler, UIControl handler (buttons, sliders), performSelector, CADisplayLink, NSTimer events, Gesture Recognizer, accelerometer handler, and UIView animation completion block, and some other ones.
Are all of them in the same thread? That is, only one of them can be running at the same time?
Can some other method or handler be part of another thread and therefore can create race conditions?
In general, you'll find that most simple applications on iOS tend to perform almost every action on the main thread. As you noted, the instant that you bring multithreading into the picture you add another set of tricky issues to watch out for. Many developers don't want to bother with this added complexity, or are unfamiliar with GCD or threading in general, so they avoid doing anything on a background thread or GCD queue.
Several of the items you list in your question involve interactions with UIKit, and in general those interactions must occur on the main thread (iOS 4.x added the ability to perform some drawing functions in the background, though). You receive touch and other related events on the main thread. If you wish to update most aspects of an interface, the safe way to do that is by performing these updates on the main thread.
Timers (NSTimer, CADisplayLink) can have their updates be fired on a background thread by attaching them to an NSRunLoop operating on that background thread. You rarely see people do this, but it can be done. Usually, people configure timers on the main run loop, which causes callbacks to be delivered on the main thread.
When performing animations, the animations themselves will run on a background thread (you see that they don't stop while you're blocking the main thread with something else), but you'll almost always receive a completion block or callback on the main thread when they're done. If I remember correctly, there are one or two exceptions to this and they are noted as such in Apple's documentation. Having these callbacks trigger on the main thread is a safe approach when dealing with developers who might not realize what's going on behind the scenes.
All that said, there are very good reasons to want to add multithreading to your application. Because all user interface updates and touch interactions occur on the main thread, if you have something that is computationally expensive or that simply will take a lot of time to perform, if you run this on your main thread you'll appear to have frozen your application. This is a terrible user experience, so you want to move this task onto a background thread so that the user can keep interacting with your application while this is going on. Additionally, more and more iOS devices are shipping every day with multiple cores in them, and balancing your work load across these cores and being efficient with this hardware requires some degree of concurrent processing.
People have written books about best practices when making code multithreaded, and you can find a lot of questions about this here, so I won't go into too much detail. What I can tell you is that you should read Apple's Concurrency Programming Guide and watch the WWDC videos from the last two years that deal with Grand Central Dispatch. With GCD, Apple has made it a lot easier to add multithreading to your application in an efficient and (relatively) safe manner, and I encourage you to look into this for your own applications.
For example, I have an open source iOS application that performs detailed rendering of molecular structures. I render each frame on a background GCD queue because sometimes they take more than 1/60th of a second to process, and in those cases they'd cause touch events to be dropped and the interface to stutter if this was all on the main thread. Additionally, I've seen up to a 40% performance boost by doing this when running on the newer multicore devices. To avoid race conditions, I wrap interactions with shared data structures and contexts in serial dispatch queues so that only one action can be using a resource at a time, no matter what thread a particular block is running on. This only required the addition of a few lines of code, but the performance and user experience benefits were huge.

Resources