Many long running async methods have completion handler blocks attached as input parameters to them
I'm not sure if the completion handler should be called if the operation was cancelled.
-(void)longRunningAsyncOperation:(Input *)input completionHandler:(Block)completionHandler
{
// long running code
// periodic checks for cancelation
if(_canceled)
{
// should completion handler still be called?
return;
}
// more long running code
// completed
completionHandler(someData);
}
I don't think there's necessarily one "right answer" here. You should just make it do whatever you need to do. One option, as #Fogmeister proposed in a comment is to make the completion routine take an argument indicating whether it was canceled or completed normally. It would seem advisable to have something called in all cases so that an interested party can know that the operation was canceled.
I've seen other APIs that take two different completion blocks -- a "success" block and a "failure" block. To my mind, a single block that takes arguments to indicate status seems like a more adaptable pattern.
If you don't call any completion block on cancelation then there is effectively "lost information"; absent some other mechanism, it's impossible for the outside world to know that the operation was canceled, so it seems like one of these patterns, be it an argument to the completion, or success/failure blocks, would be preferable to simply not calling anything.
#ipmcc is correct. There is generally no one right answer, but best practices generally dictates that you should always call the completion block and, if the completion block actually cares, pass it a success/cancelled flag. The reason this is a best practice is that some memory may have been allocated as a prelude to the cancelled operation and if you don't call the completion handler, you'll never have the opportunity to free it again.
I would say yes, it shall call the completion handler.
The rationale for this is, that one can view a completion handler as some form of return value.
So, not calling the completion handler is like not returning a value in a function which is declared to return something.
Related
In iOS, we have GCD and Operation to handle concurrent programming.
looking into GCD we have QoS classes, and they're simple and straight forward, this question is about why DispatchQueue.main.async is commonly used to asynchronies X tasks in the Main Thread.
So when we usually handle updating something in the UI we usually use that function since to prevent any irresponsiveness from the application.
makes me think is writing code inside the UIViewController usually executed in the main thread ?
but also knowing that callback & completionHandler usually execute without specifying on what thread they are in, and the UI never had a problem with that !! so it is on the background ?
How Swift handles this ? and what thread am i writing on by default without specifying anything ?
Since there are more than one question here, let's attempt to answer them one by one.
why DispatchQueue.main.async is commonly used to asynchronies X tasks
in the Main Thread.
Before mentioning a direct answer, make sure that you don't have confusion of understanding:
Serial <===> Concurrent.
Sync <===> Async.
Keep in mind that DispatchQueue.main is serial queue. Using sync or async has nothing to do with determining serialization or currency of a queue, instead they refer to how the task is handled. Thus saying DispatchQueue.main.async means that:
returns control to the current queue right after task has been sent to
be performed on the different queue. It doesn't wait until the task is
finished. It doesn't block the queue.
cited from: https://stackoverflow.com/a/44324968/5501940 (I'd recommend to check it.)
In other words, async means: this will happen on the main thead and update it when it is finished. That's what makes what you said:
So when we usually handle updating something in the UI we usually use
that function since to prevent any irresponsiveness from the
application.
seems to be sensible; Using sync -instead of async- will block the main.
makes me think is writing code inside the UIViewController usually
executed in the main thread ?
First of all: By default, without specifying which thread should execute a chunk of code it would be the main thread. However your question seems to be unspecific because inside a UIViewController we can call functionalities that are not executed on the main thread by specifying it.
but also knowing that callback & completionHandler usually execute
without specifying on what thread they are in, and the UI never had a
problem with that !! so it is on the background ?
"knowing that callback & completionHandler usually execute without specifying on what thread they are in" No! You have to specify it. A good real example for it, actually that's how Main Thread Checker works.
I believe that there is something you are missing here, when dealing when a built-in method from the UIKit -for instance- that returns a completion handler, we can't see that it contains something like DispatchQueue.main.async when calling the completion handler; So, if you didn't execute the code inside its completion handler inside DispatchQueue.main.async so we should assume that it handles it for you! It doesn't mean that it is not implemented somewhere.
Another real-world example, Alamofire! When calling
Alamofire.request("https://httpbin.org/get").responseJSON { response in
// what is going on here work has to be async on the main thread
}
That's why you can call it without facing any "hanging" issue on the main thread; It doesn't mean its not handled, instead it means they handle it for you so you don't have to worry about it.
I am new to swift and trying to learn when I saw apple doc in it there is a definition about escaping closure like:
A closure is said to escape a function when the closure is passed as an argument to the function, but is called after the function returns. When you declare a function that takes a closure as one of its parameters, you can write #escaping before the parameter’s type to indicate that the closure is allowed to escape.
# other hand I saw a blog where blogger explained about completion handler like:
There are times you put a closure as one of the parameters, but you only want to execute the closure after the function returns. For example, what if you want to print “Hello, world” only after you’ve completely switched to the next ViewController?
So I want to know if completion handler and escaping closure are same or what?
I want to know that completion handler and escaping closure are same
or what?
Completion and Error Handlers are related to a process that should be done after executing -and returning- a chunk of code (function):
Completion handlers are callbacks that allow a client to perform some
action when a framework method or function completes its task.
https://developer.apple.com/library/content/featuredarticles/Short_Practical_Guide_Blocks/
which are -logically- representation of escaping closures.
So, referring to the escaping closures definition, a completion handler is by default is an escaping closures.
For reviewing example(s), you might want to check this answer. Also, if you think that you need more description about what is the escaping closure, you might wan to check this Q&A.
Completion handlers are one example where escaping closures are passed, but they are not the only one.
In fact, the concept of a completion handler works on a different level than the concept of an escaping closure.
Escaping Closure
The closure is stored, and may be invoked at some time in the future.
This is in contrast to a non-escaping closure, where the closure gets called immediately or not at all.
The difference between escaping and non-escaping closure is important for memory management. For non-escaping closures, the compiler knows that any resources used by the closure aren't used anymore after the call.
Completion Handler
A completion handler is a closure that gets called once an operation is finished.
Operations that use completion handlers often are long-running and work on different threads. While such an operation is running, your program can continue with its control flow, thereby making the program more responsive. For example, if you call URLSession.downloadTask(withResumeData:completionHandler:), you will schedule a new download task in URLSession. Downloading may take a while, depending on your connectivity status and other factors, and only once the download was finished your completion handler gets called.
The way such operations are implemented is usually, that they store the completion handler somewhere, perform the operation, and then call the completion handler. Therefore, completion handlers are usually escaping closures.
I have an NSOperation and in the completionblock I do some time consuming saving to CoreData. The actual operation runs fast. Occasionally I need to prevent this completetionblock from running. I can't see an easy way to cancel it so I tried setting a BOOl and skipping the code within it if necessary. However the operation is run within a singleton and another class needs to run the queue (that's why I need to cancel the completionblock). Any ideas on how I can cancel the completeionblock?
You can simply set completionBlock to nil:
operation.completionBlock = nil
But I think that cancelling operation's completion block from another class might be a design smell. You can end up with code which is hard to maintain and debug, as it's not clear why and when the operation's flow was changed.
An NSOperation that runs fast with a time consuming completion block seems wrong. NSOperation can be cancelled, that's its main purpose. blocks cannot be cancelled unless you do all the work itself.
I'd suggest creating a subclass of NSOperation which does all the work, including what is now done in the completion block, and the code that is now in the completion block can check that it is cancelled.
On the other hand, "saving to CoreData" doesn't seem to be something you can just cancel half way through, so the better suggestion might be to take a step back and figure out what you actually want to happen.
You can cancel the operation by calling cancel method of NSOperation.
[operation cancel];
I realize this question sounds contradictory. I have several Async requests going out in an application. The situation is that the first async request is an authentication request, and the rest will use an access token returned by the successful authentication request.
The two obvious solutions would be:
run them all synchronous, and risk UI block. (bad choice)
run them async, and put request 2-N in the completion handler for the first one. (not practical)
The trouble is that the subsequent requests may be handled anywhere in the project, at anytime. The failure case would be if the 2nd request was called immediately after the 1st authentication request was issued, and before the access token was returned.
My question thus is, is there any way to queue up Async requests, or somehow say not to issue them until the first request returns successfully?
EDIT:
Why (2) is not practical: The first is an authentication request, happening when the app loads. The 2nd+ may occur right away, in which case it is practical, but it also may occur in a completely separate class or any other part of a large application. I can't essentially put the entire application in the completion handler. Other accesses to the API requests may occur in other classes, and at anytime. Even 1-2 days away after many other things have occurred.
SOLUTION:
//pseudo code using semaphore lock on authentication call to block all other calls until it is received
// at start of auth
_semaphore = dispatch_semaphore_create(0)
// at start of api calls
if(_accessToken == nil && ![_apiCall isEqualToString:#"auth]){
dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);
}
// at end of auth with auth token
dispatch_semaphore_signal([[SFApi Instance] semaphore]);
_accessToken = ...;
This sounds like a case where you'd want to use NSOperation's dependencies
From apple docs:
Operation Dependencies
Dependencies are a convenient way to execute operations in a specific order. You can add and remove dependencies for an operation using the addDependency: and removeDependency: methods. By default, an operation object that has dependencies is not considered ready until all of its dependent operation objects have finished executing. Once the last dependent operation finishes, however, the operation object becomes ready and able to execute.
note that in order for this to work, you must subclass NSOperation "properly" with respect to KVO-compliance
The NSOperation class is key-value coding (KVC) and key-value observing (KVO) compliant for several of its properties. As needed, you can observe these properties to control other parts of your application.
You can't really have it both ways-- there's no built-in serialization for the NSURLConnection stuff. However, you are probably already funneling all of your API requests through some common class anyway (presumably you're not making raw network calls willy-nilly all over the app).
You'll need to build the infrastructure inside that class that prevents the execution of the later requests until the first request has completed. This suggests some sort of serial dispatch queue that all requests (including the initial auth step) are funneled through. You could do this via dependent NSOperations, as is suggested elsewhere, but it doesn't need to be that explicit. Wrapping the requests in a common set of entry points will allow you to do this any way you want behind the scenes.
In cases like this I always find it easiest to write the code synchronously and get it running on the UI thread first, correctly, just for debugging. Then, move the operations to separate threads and make sure you handle concurrency.
In this case the perfect mechanism for concurrency is a semaphore; the authentication operation clears the semaphore when it is done, and all the other operations are blocking on it. Once authentication is done, floodgates are open.
The relevant functions are dispatch_semaphore_create() and dispatch_semaphore_wait() from the Grand Central Dispatch documentation: https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html#//apple_ref/doc/uid/TP40008079-CH2-SW2
Another excellent solution is to create a queue with a barrier:
A dispatch barrier allows you to create a synchronization point within a concurrent dispatch queue. When it encounters a barrier, a concurrent queue delays the execution of the barrier block (or any further blocks) until all blocks submitted before the barrier finish executing. At that point, the barrier block executes by itself. Upon completion, the queue resumes its normal execution behavior.
Looks like you got it running with a semaphore, nicely done!
Use blocks... 2 ways that I do it:
First, a block inside of a block...
[myCommKit getPlayerInfoWithCallback:^(ReturnCode returnCode, NSDictionary *playerInfo) {
if (playerInfo) {
// this won't run until the first one has finished
[myCommKit adjustSomething: thingToAdjust withCallback:^(ReturnCode returnCode, NSDictionary *successCode) {
if (successCode) {
// this won't run until both the first and then the second one finished
}
}];
}
}];
// don't be confused.. anything down here will run instantly!!!!
Second way is a method inside of a block
[myCommKit getPlayerInfoWithCallback:^(ReturnCode returnCode, NSDictionary *playerInfo) {
if (playerInfo) {
[self doNextThingAlsoUsingBlocks];
}
}];
Either way, any time I do async communication with my server I use blocks. You have to think differently when writing code that communicates with a server. You have to force things to go in the order you want and wait for the return success/fail before doing the next thing. And getting used to blocks is the right way to think about it. It could be 15 seconds between when you start the block and when it gets to the callback and executes the code inside. It could never come back if they're not online or there's a server outage.
Bonus way.. I've also sometimes done things using stages:
switch (serverCommunicationStage) {
case FIRST_STAGE:
{
serverCommunicationStage = FIRST_STAGE_WAITING;
// either have a block in here or call a method that has a block
[ block {
// in call back of this async call
serverCommunicationStage = SECOND_STAGE;
}];
break;
}
case FIRST_STAGE_WAITING:
{
// this just waits for the first step to complete
break;
}
case SECOND_STAGE:
{
// either have a block in here or call a method that has a block
break;
}
}
Then in your draw loop or somewhere keep calling this method. Or set up a timer to call it every 2 seconds or whatever makes sense for your application. Just make sure to manage the stages properly. You don't want to accidentally keep calling the request over and over. So make sure to set the stage to waiting before you enter the block for the server call.
I know this might seem like an older school method. But it works fine.
I'm learning about blocks from a Stanford video. I'm now at the part which explains core data. The teachers mentions something about:
- (void)openWithCompletionHandler:(void (^)(BOOL success))completionHandler;
He said that completionhandler block will be called in the thread which called the method. So basically the method runs async but the blocks get called on the thread, lets assume main.
So my question is do all blocks run on the thread from where the method call was made. To illustrate why I ask this question, I have a Async class which does request to a server.
The format of all these methods is like this:
- (void) getSomething:(id <delegateWhatever> const)delegate{
goto background thread using GCD..
Got result from server...
Go back to main thread and call the delegate method...
}
When I use blocks I do not need to worry about going back to main thread if they will be called where the call was made?
Hope this is clear,
Thanks in advance
If something runs asynchronously, you should read a documentation to know on which thread, e.g. the completion block will be executed. If it is your code, you are in charge here, you can use global GCD queues, you can create your own queue and execute it there or whatever...
In general, blocks behaves like a function or a method call, it is executed on thread, which calls it. It is even possible that the same block will be executed from 2 different threads at the same time.
And just to be clear: Even if you are using blocks, you need to care about going back to main thread, of course if it is necessary
Nothing forces blocks to be called on a particular thread, so it depends on the specific method whether or not you need to worry about its callback being on the main thread. (In practice I don't remember ever seeing a library where a method called on the main thread would not call its completion handler also on the main thread. But you still need to read the documentation of the specific library and method you are using, as always.)