How to write a completion handler for when the SCNAction ends? Or maybe just get notified when the action ends. Is is any way to know when the action ended? My last resort is to use custom delay(delay: Double, closure:()->()) function with delay set to actions execution time, but that seems rather fragile.
runAction(_:completionHandler) and runAction(_:forKey:completionHandler) accept closures. They're defined on the SCNActionable protocol, not SCNAction, so the documentation is easy to miss.
https://developer.apple.com/reference/scenekit/scnactionable/1524219-runaction
Related
What is the use of -
func perform(_ aSelector: Selector!) -> unmanaged<AnyObject>!
in iOS?
To call a method of a class?
To add a selector method?
To add a class delegate?
To define a class? (I doubt it's this)
I was originally thinking that it it was to add a selector method, but after looking at it some more I think it may be "to call a method of a class." Selectors are used for target/action paradigms where I kick something off and when the event fires or finishes then it wants to fire off some kind of action method.
In this example do I pass it a parameter of a selector function then at the end of this "perform" function, I am returning an unmanaged object of any type? Does that even make sense?
Thanks!
In Swift this is basically useless. It's bridged from Objective-C, where it used to be very useful (before ARC), but now it's a bit tricky.
The point of it is to send a message by name and get a result. Generally speaking that translates to calling a method of that name.
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.
How do I set a completion event on the SpeakUtterance(utterance) function in Swift? I need this so that my speech is neither interrupted nor interrupting.
Have you looked at the header (or generated Swift interface) for AVSpeechSynthesizer? Or its documentation? Looks pretty straightforward there...
Set an instance of one of your classes as the delegate of the speech synthesizer.
In that class, implement the speechSynthesizer(_:didFinishSpeechUtterance:) method. It'll be called whenever an utterance finishes speaking.
There's no step three.
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];
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.