How do I call animateAlongsideTransition in Swift? - ios

I've tried so many combinations in order to call animateAlongSideTransition in Swift for a transition coordinator. I feel like I'm missing something very stupid.
If I want to call this (from Swift docs):
func animateAlongsideTransition(_ animation: ((UIViewControllerTransitionCoordinatorContext!) -> Void)!,
completion completion: ((UIViewControllerTransitionCoordinatorContext!) -> Void)!) -> Bool
How would I do it? I just want to pass some things in the animation block and nothing in the completion block.

This is definitely what you want to do:
coordinator.animateAlongsideTransition({ context in
// do whatever with your context
context.viewControllerForKey(UITransitionContextFromViewControllerKey)
}, completion: nil)
You can also omit the parameters if you use variables like $0 for the first implicit parameter and so
coordinator.animateAlongsideTransition({
$0.viewControllerForKey(UITransitionContextFromViewControllerKey)
}, completion: nil)
The in syntax surprises at first, but you have to learn it only once :)
The curly brackets defines the block inside the function
You use in to separate the parameters from the block body
But as I said above, you can omit the parameters by using $0, $1, $2 and so...
It seems that there's a more verbose syntax, but it definitely not fits the Swift spirit (and I'm too lazy to post it there)
Hope it helps (and I don't forget anything...)
Edit:
Another pro tip is when the block is the only parameter, you can even omit the parentheses
(The next will not work, but it's to figure the idea)
coordinator.animateAlongsideTransition{
$0.viewControllerForKey(UITransitionContextFromViewControllerKey)
}

You do it like this (at least in Swift 1.2):
transitionCoordinator.animateAlongsideTransition({context in //things to animate, for example: view.alpha = 0.5
}, completion: nil)

Related

Swift Combine two handlers for one property

I have a UIViewController which using UITableViewDiffableDataSource. I have a view-model for this controller which looks something like:
class ListViewModel {
#Published private(set) var items: [Item] = []
func load(params: [String: Any] = [:]) {
WebRepo().index(params: params, completion: { [weak self] (items, error) in
self?.items = items
})
}
func deleteFirst() {
self.items.remove(object: self.items.first)
}
}
In my VC, I have a binding like:
self.viewModel.$items.sink { [weak self] (scenes) in
self?.update(items: items, animated: false)
}.store(in: &self.subscriptions)
So, when I'm calling my view-model's load method - I want to do self?.update(items: items, animated: false), but when I'm calling deleteFirst - I want self?.update(items: items, animated: true).
I'm quite new to reactive and Combine, so not sure what is the proper way to handle this.
I can add isReset property to my view-model and change load method to something like:
func load(params: [String: Any] = [:]) {
WebRepo().index(params: params, completion: { [weak self] (items, error) in
self?.isReset = true
self?.items = items
self?.isReset = false
})
}
And inside sink just check this property, but it does not look as a proper way for me.
Here's one way of thinking about it. Instead of publishing items, use a PassthroughSubject whose output type is a tuple, ([Items], Bool). And the view controller subscribes to that subject.
Now, when you call load, call the passthrough subject's send with (items, false), but when you call delete, call the passthrough subject's send with (items, true).
In other words, take it upon your publisher to publish all the information that the downstream would need in order to know what to do.
You might think that this approach is rather extreme, but clumping things together into a tuple in order to pass multiple pieces of info down the pipeline is normal behavior. Really, this is the reactive equivalent of calling a method with two parameters.
Another possibility might be for the downstream to consider how many times this publisher has published. This would work if, for example, the ViewModel is going to call load only once. If that's the case, the downstream pipeline would be able to use operators (such as scan, or first, or whatever) to distinguish the first value that comes down the pipeline (which means we want not to animate) from any subsequent values (where we do want to animate).
Yet another way to think of this would be to put the onus entirely on whoever is building the snapshot. If the diffable data source's snapshot is empty, it has no data and we do not want to animate. If is not empty, we do want to animate. Again, that would work only if applicable to your purposes.

Different types of closure syntax in swift - which one is correct?

I'm pretty curious which one of these syntax statements is (more) correct.
Playground happily compiles both cases.
Method 1
// copied from SO and this appears clear to me
UIView.animate(
withDuration: 3.0,
animations: {
},
completion: { (Bool) in
// completion code
}
)
Method 2
UIView.animate(
withDuration: 3.0,
animations: {
// code
}) {(Bool) in
// code when finished?
// argument label completion missing?
}
Why rounded brackets in 2nd method are closed before last argument stated? Or is that another implementation of UIView.animation?
Both of them are correct.
It is the usual closure syntax in a function call.
It represents a Trailing closure.
If you need to pass a closure expression to a function as the
function’s final argument and the closure expression is long, it can
be useful to write it as a trailing closure instead. A trailing
closure is written after the function call’s parentheses, even though
it is still an argument to the function. When you use the trailing
closure syntax, you don’t write the argument label for the closure as
part of the function call.
You can read more about trailing closures from https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html
The difference between both methods is following:
Method 1: Regular closure
Method 2: Trailing closure.
Last closure parameter in the signature of a function can be written in shorter syntax. If the second parameter would be completion, and animations parameter would be the last, the trailing closure would apply to animations etc.
So it has to stand as the last (or the only) closure parameter.
If you miss a completion label, you are free to type it like this:
UIView.animate(withDuration: 3.0, animations: {
}) {(completion: Bool) in
}
For completion of your question as well: It is the same implementation of an identical function, but a different syntax.

When to use closures in swift? [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 7 years ago.
Improve this question
I am been to ios development for few months and eager to implement new things in my programming pattern.
Now i am learning closures and knew little things about its syntax,knew it can be used instead of delegate for callbacks. As well as implemented it in some UIViewAnimation and for sorting.
But really i want to know its uses apart from that.i.e where should we use closures in our basic programming. Like we use delegate when we want to send information from child to parent.. So any explanation or brief example on its actual which can be used in our day to day swift programming would be helpful?
Can anyone tell me how these closure actually computes the value
reversed = sorted(names, { (s1: String, s2: String) -> Bool in return s1 > s2 } )
In these example there is names and closure as an argument to a method..but how does this actually computes ?
Can you please explain how these works when passing closures in this animation code :
UIView.animateWithDuration(duration: NSTimeInterval,
animations: (() -> Void)?,
completion: ((Bool) -> Void)?)
I really want to know about the flow?
The two most used cases are completion blocks and higher order functions in Swift.
Completion blocks: for example, when you have some time consuming task, you want to be notified when that task is finished. You can use closures for that, instead of a delegate (or many other things)
func longAction(completion: () -> ()) {
for index in veryLargeArray {
// do something with veryLargeArray, which is extremely time-consuming
}
completion() // notify the caller that the longAction is finished
}
//Or asynch version
func longAction(completion: () -> ()) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
for elem in veryLargeArray {
// do something with veryLargeArray, which is extremely time-consuming
}
dispatch_async(dispatch_get_main_queue(), {
completion() // notify the caller that the longAction is finished
})
}
}
longAction { print("work done") }
In the example above, when you have a time consuming task, you want to know when the for loop finishes iterating through the very large array. You put the closure { println("work done") } as an input parameter for the function which will be executed after the for loop finishes its work, and print "work done". And what happened is that you gave a function (closure) to longAction and name it to completion, and that function will be executed when you call completion in longAction.
Higher order functions: you can use closures as input parameters for higher order functions, for example:
let array = [1, 2, 3]
let smallerThanTwo = array.filter { $0 < 2 }
With this, you can filter out the numbers that are smaller than 2.
UPDATED About how sorted (probably) works:
So the idea is, that sorted will go through the array, and compare two consecutive elements (i, i + 1) with each other, and swap them, if needed. What does it mean "if needed"? You provided the closure { (s1: String, s2: String) -> Bool in return s1 > s2 }, which will return true if s1 is lexiographically greater than s2. And if that closure returned true, the sorted algorithm will swap those two elements, and countinues this with the next two elements (i + 1, i + 2, if the end of the array is not reached). So basically you have to provide a closure for sorted which will tell "when" to swap to elements.
A closure is something like:
{ (params) -> returnType in
statements
}
Here are some reasons why to use it from the Apple doc
Inferring parameter and return value types from context
Implicit returns from single-expression closures
Shorthand argument names
Trailing closure syntax
Usually Closures does not has names in contrast to other functions. That means them can be used in every case when you want to pass chunk of code to some function without wrapping that code into named method. Sorting is the most popular example.
Closures can use variables outside of its borders. So called "Capturing Values"

Why will func closures sometimes delete its paramter name in Swift?

I have a function of two closures
testNetworkAvailability(reachableBlock:, unreachableBlock:)
But when I hit enter for the autocompletion of closure placeholder, the second one unreachableBlock will delete the variable name along with it and causes an error.
For example, if I open up this closure placeholder by hitting enter, it will look like:
testNetworkAvailability(reachableBlock: { () -> Void in
<#code#>
}) { () -> Void in
<#code#>
}
As a matter of fact, as I copy this function to stackoverflow, the placeholder for these blocks reads as <#(() -> Void)?##() -> Void#>. It is so strange as it should be #() -> Void# only, shouldn't it?
Why is this and how to fix it?
As long as the last argument is a closure, Swift allows you to omit the parameter name and treat it as an inline block.
autoreleasepool {
// ...
}
See the documentation on trailing closures.
Should XCode's autocomplete prefer trailing closures than not is a topic for debate however.

UIView.animateWithDuration completion

I have a question concerning the swift implementation of the method mentioned in the title. If I do this:
leadingSpaceConstraint.constant = 0
UIView.animateWithDuration(0.3, animations: {
self.view.layoutIfNeeded()
}, completion: { (complete: Bool) in
self.navigationController.returnToRootViewController(true)
})
I get the following problem: Missing argument for parameter 'delay' in call. This only happens if I have the self.navigationController.returnToRootViewController() in the completion part. If I extract that statement into a seperate method like this:
leadingSpaceConstraint.constant = 0
UIView.animateWithDuration(0.3, animations: {
self.view.layoutIfNeeded()
}, completion: { (complete: Bool) in
self.returnToRootViewController()
})
func returnToRootViewController() {
navigationController.popToRootViewControllerAnimated(true)
}
Then it works perfectly and does exactly what I want. Of course this does not seem to be the ideal solution and more like a work around. Can anyone tell me what I did wrong or why Xcode (beta 6) is behaving this way?
I presume you mean popToRootViewControllerAnimated in your first snippet, since returnToRootViewController isn't a method on UUNavigationController.
Your problem is that popToRootViewControllerAnimated has a return value (the array of view controllers removed from the navigation stack). This causes trouble even though you're trying to discard the return value.
When Swift sees a function/method call with a return value as the last line of a closure, it assumes you're using the closure shorthand syntax for implicit return values. (The kind that lets you write things like someStrings.map({ $0.uppercaseString }).) Then, because you have a closure that returns something in a place where you're expected to pass a closure that returns void, the method call fails to type-check. Type checking errors tend to produce bad diagnostic messages — I'm sure it'd help if you filed a bug with the code you have and the error message it's producing.
Anyhow, you can work around this by making the last line of the closure not be an expression with a value. I favor an explicit return:
UIView.animateWithDuration(0.3, animations: {
self.view.layoutIfNeeded()
}, completion: { (complete: Bool) in
self.navigationController.popToRootViewControllerAnimated(true)
return
})
You can also assign that popToRootViewControllerAnimated call to an unused variable or put an expression that does nothing after it, but I think the return statement is clearest.

Resources