Date
1 - 10 of 10
dispatch_async question
Dave
Hi All,
In the following code, does it *need* to use the dispatch_async function? dispatch_async(dispatch_get_main_queue(), ^{ if ([[self delegate] respondsToSelector:@selector(gameCenterManager:availabilityChanged:)]) [[self delegate] gameCenterManager:self availabilityChanged:successDictionary]; }); It sometimes uses it and sometimes it calls the delegate inline. I’m wondering why? As far as I am aware, the only thing using dispatch_async does, is call the delegate sometime after the current method as returned, which I can’t see is of any benefit and makes things much hard to understand. Am I missing something? This code is attempting to authenticate a Game Center Player, (the whole method is copied below), it may prompt the user to authenticate, I’m wondering if its something to do with this, although again, I can’t see that dispatch_async is necessary or or is of any benefit? I’m trying to debug my Game Center Code and decided to see how someone else did it, but I’m getting more confused by the minute, All the Best Dave |
|
Fritz Anderson
On Jul 19, 2017, at 8:30 AM, Dave <dave@...> wrote:
It's hard to understand because concurrency is the most difficult task in software engineering. (A debate on "hardest task" might be fun. Please let's not.) If the code you're looking at was thoughtfully-written, the decision to dispatch or not was deliberate. UI work must be done on the main thread, one operation at a time — in other words, serially, which is easier if you have a queue manager to make sure everything happens in turn. Letting multiple threads interrupt each other as they force a label to change its layout will end badly. The original code assumes the delegate may require the main thread. ## Assume the caller is **guaranteed** to be on the main thread The assumption is not to be made lightly. If it's true, this is easy. Call directly. There may be further issues (do not monopolize the UI thread) but those are beyond the scope of your question. ## Assume the caller might not be on the main thread The work has to be done on the main thread (so the original code assumes). You must use GCD to hand it over to the main dispatch queue. The main queue makes sure the work gets its turn with no interference. That answers the literal question of why the code is sometimes dispatched, sometimes not. The decisions and the design that drove them (such as why "do it later" may also be the right strategy) are much harder. You can learn, but not in a single email. — F |
|
Alex Zavatone
On Jul 19, 2017, at 9:51 AM, Fritz Anderson <anderson.fritz@...> wrote:I’m glad that Fritz chimed in here before I risked an answer. My gut feeling was that, “well, even if it isn’t required, seeing the word ‘_async’ in the function clearly states to you that the intent of the operation is for it to be async - no assumption by the programmer is needed.” It’s kind of like, “well, even if it isn’t needed, it’s certainly clearer to whomever is writing or reviewing the code.” I think that if you are following the debugger, and observing what is happening, the results may be confusing when observing what the debugger is telling you. This is one of the things I have learned to accept, assuming that I will figure it out later, if needed. Is that the case, Dave? - Alex Zavatone |
|
The call you showed runs the block on the main thread. That aspect may be crucial. Does the code this is part of run on a different thread/queue? Also, it can often be very useful to defer some code until after the current event completes; this is often called a “delayed perform” because the old school way to do it is by calling -performSelector:withObject:afterDelay:. An async dispatch to the current queue is the moral equivalent. In the case of this statement, I couldn’t tell you why this is useful without knowing more about the code overall. —Jens |
|
Sak Wathanasin
The "Main thread checker" in XC 9 beta will tell you if you're doing something off the main thread that you shouldn't. It's really useful. |
|
Dave
HI,
The thing is the code is being called Asynchronously anyway, I think the point was that this code assumes that that the delegate needs to run on the Main Thread, which in my mind is just as bad as assuming it won’t. In some cases the calls to the delegate *may* have to be on the main thread, but surely that decision is best made by the delegate itself, since, it really depends on what the delegate method itself is doing as to if it needs to be run on the main thread or not. All the Best Dave
|
|
On 22 Jul 2017, at 3:51 am, Dave <dave@...> wrote:Any class that supports a delegate inherently understands its own threading behaviour, and thus can (should) articulate the policy under which it will call its delegates. It looks like your code uses or is based on https://github.com/nihalahmed/GameCenterManager (thanks Google), so it seems to me that GameCenterManager should assure you one way or the other what to expect as its delegate implementor; if it doesn't, it seems like a documentation oversight. b |
|
Dave
Hi,
It looks like your code uses or is based on https://github.com/nihalahmed/GameCenterManager (thanks Google),No, but I looked at it to see how to setup Game Center, I have a similar Class but its uses the Turn Based Classes/Delegates. The thing is, in my case, it actually doesn’t matter if its run on the Main thread or not, since the delegate its calling does not itself do any UI work. I think that GameCenterManager is assuming that the delegate is a View Controller, whereas in my case it isn’t. I have an AppManager Class in the middle that acts as a “middleman” it is a delegate of Game Center, the Game Engine and the Game View Controller, that way its much easier to keep everything in sync…. So, I only need to use the main thread for Messaging being sent to the View Controller and the View Controller itself ensures that it runs on the correct thread. All the Best Dave On 23 Jul 2017, at 20:00, Ben Kennedy <ben@...> wrote:On 22 Jul 2017, at 3:51 am, Dave <dave@...> wrote:Any class that supports a delegate inherently understands its own threading behaviour, and thus can (should) articulate the policy under which it will call its delegates. |
|
Fritz Anderson
For the archive, "UI" is the largest group of API that can't be backgrounded, and the easiest to explain. There are many other such interfaces.
toggle quoted message
Show quoted text
The hard (both inflexible and difficult) rule is that any entry is thread-unsafe unless documented otherwise. Safety or un-safety may be documented specifically, or only once at the top of a framework or class. Or it's implicit. Or it's wrong. Third-party frameworks are rarely documented or stable for threading, though well-curated ones are better about it. Behavior under unsafe use is undetermined; in the worst case it works as expected _almost_ every time. Whether, how, and how often an unsafe call fails may change without notice at any point release of the OS or a library. This is what makes an API of tens of thousands of symbols such an engrossing pastime. I'm not at all questioning Dave's use of the API. This is for the search engines and the archive. — F On Jul 24, 2017, at 7:44 AM, Dave <dave@...> wrote: |
|
Dave
The thing is, in my case, it actually doesn’t matter if its run on the Main thread or not, since the delegate its calling does not itself do any UI work. I should have probably said - “it actually doesn’t matter if its run on the Main thread or not, since the delegate its calling is thread safe”. The class that the delegate calls to update the UI isn’t thread safe, but I think its better to handle its threading requirements in the View Controller itself, since the Game Engine is also Thread Safe….. All the Best Dave |
|