How to pass argument to multiple trailing closures? - swift

I want to print "voala" within both closures, however it gets error: Cannot find 'sound' in scope. I found similar example in book, however it does not work, therefore asking.
func multipleTrailing(scream sound: String, first closure1: () -> Void, second closure2: () -> Void) {
closure1()
closure2()
}
multipleTrailing(scream: "voala") {
print("\(sound), calling from closure1, omitting argument label \"first\"")
} second: {
print("\(sound), calling from closure2, keeping argument label \"second\"")
}

You should give the value to the closures. Here both closures have an input parameter of a String type, and the multipleTrailing function gives the sound parameter to both of them. On the caller site this parameter can have any name (here I gave them sound in both places), and you can access those values
func multipleTrailing(scream sound: String, first closure1: (String) -> Void, second closure2: (String) -> Void) {
closure1(sound)
closure2(sound)
}
multipleTrailing(scream: "voala") { sound in
print("\(sound), calling from closure1, omitting argument label \"first\"")
} second: { sound in
print("\(sound), calling from closure2, keeping argument label \"second\"")
}

Related

How to get function's parameter value without parameter name in swift?

func test(_: [Int]) {
print("xxx")
}
test([1,2,3])
I saw this code is valid in swift, how can I get the value passed into test?
To explicitly answer your question:
how can I get the value passed in test?
You can't, in the same way that after
let _ = someFunction()
you have no way to get at the return value of someFunction. That's really the whole point of _ which basically means "I'm ignoring this intentionally".
In order to get the parameter value inside the function, you have to specify the parameterName. Swift's function has this kind of structure :
func someFunction(argumentLabel parameterName: Int) {
// In the function body, parameterName refers to the argument value
// for that parameter.
}
where argumentLabel is used on the function caller, for example
func eat(byWhom person: String){}
would become
eat(byWhom: "Victor")
in the caller code.
On the other hand, you can get the "Victor" value from the parameterName :
func eat(byWhom person: String){
print(person) // should print "Victor"
}
create function like this
func test(_ value: [Int]) { }
and then you can call it like this.
test([1,2]) without mentioning the parameter name.
There's no chance to get functions parameter value w/o its name. That is why it is being used. But you can do this:
func test(_ value: [Int]) {
print(value)
}
test([1,2,3])

How can I change an inout parameter from within a escaping closure?

I was trying to modify a parameter of function from within a escaping closure as below:
var completion = [()->Void]()
func addCompletion(closure: #escaping ()->Void) {
completion.append(closure)
}
func testAdd(v: inout Int) {
addCompletion{
v = 1 // Compiler tells 'Escaping closure captures 'inout' parameter 'v'
print("hello1 \(v)")
}
}
var x = 0
testAdd(v:&x)
for comp in completion {
comp()
}
I was wondering if there is another way to let escaping closure change surrounding variable (as function's inout parameter), besides making it into reference type as a class object.
inout is specified to have a "copy-in copy-out" behaviour. The value of x is copied when you call the function. In the function body, the copy of x can be modified, or whatever. Then, when the function returns, the copy is copied again, and assigned to the original x. "Call-by-reference" could happen as an optimisation.
This explains why you can't modify an inout parameter in an escaping closure. The swift compiler can't possibly know when every escaping closure returns, to copy the modified value back.
You can use an actual pointer:
func testAdd(v: UnsafeMutablePointer<Int>) {
addCompletion{
v.pointee = 1 // you just need to change all references to "v" to "v.pointee"
print("hello1 \(v.pointee)")
}
}
Alternatively, if you don't like pointers, you can also do this trick (adapted from my other answer):
func testAdd(modifyV: #escaping ((inout Int) -> Void) -> Void) {
addCompletion{
modifyV { v in // here you can change v however you like!
v = 1
print("hello1 \(v)")
}
}
}
You just need to change the caller to:
testAdd { $0(&x) }

How to assign parameter's type of generic callback in swift?

Suppose I have following function:
func fetch<T: Codable>(completion: #escaping (_ response: SimpleResult<[T]>) -> Void) {
completion(parse(result))
}
Xcode does not show any error on above function. But how to use it? If I write following, it shows error:
fetch { result in
}
It says that "Generic parameter T could not be inferred". I suppose that I should indicate type here. But where should I write it?
You need to explicitly state the result type:
fetch { (result: SimpleResult<YOUR_CODABLE_TYPE>) in
}

Trouble with non-escaping closures in Swift 3

I have an extension Array in the form of:
extension Array
{
private func someFunction(someClosure: (() -> Int)?)
{
// Do Something
}
func someOtherFunction(someOtherClosure: () -> Int)
{
someFunction(someClosure: someOtherClosure)
}
}
But I'm getting the error: Passing non-escaping parameter 'someOtherClosure' to function expecting an #escaping closure.
Both closures are indeed non-escaping (by default), and explicitly adding #noescape to someFunction yields a warning indicating that this is the default in Swift 3.1.
Any idea why I'm getting this error?
-- UPDATE --
Screenshot attached:
Optional closures are always escaping.
Why is that? That's because the optional (which is an enum) wraps the closure and internally saves it.
There is an excellent article about the quirks of #escaping here.
As already said, Optional closures are escaping. An addition though:
Swift 3.1 has a withoutActuallyEscaping helper function that can be useful here. It marks a closure escaping only for its use inside a passed closure, so that you don't have to expose the escaping attribute to the function signature.
Can be used like this:
extension Array {
private func someFunction(someClosure: (() -> Int)?) {
someClosure?()
}
func someOtherFunction(someOtherClosure: () -> Int) {
withoutActuallyEscaping(someOtherClosure) {
someFunction(someClosure: $0)
}
}
}
let x = [1, 2, 3]
x.someOtherFunction(someOtherClosure: { return 1 })
Hope this is helpful!
The problem is that optionals (in this case (()-> Int)?) are an Enum which capture their value. If that value is a function, it must be used with #escaping because it is indeed captured by the optional.
In your case it gets tricky because the closure captured by the optional automatically captures another closure. So someOtherClosure has to be marked #escaping as well.
You can test the following code in a playground to confirm this:
extension Array
{
private func someFunction(someClosure: () -> Int)
{
// Do Something
}
func someOtherFunction(someOtherClosure: () -> Int)
{
someFunction(someClosure: someOtherClosure)
}
}
let f: ()->Int = { return 42 }
[].someOtherFunction(someOtherClosure: f)

Call a function which expects arguments with SKAction.runBlock()

I'm working with Swift and SpriteKit
I'd like to use SKAction.runBlock() to run a function that expect arguments :
class Tile : SKShapeNode
{
}
override func didMoveToView()
{
let tile = Tile()
tile.runAction(SKAction.runBlock(myFunc(tile)))
}
func myFunc(tile: Tile)
{
}
When I try to create a function that doesn't expect any argument, everything works fine, but the code above returns this:
Cannot convert value of type '()' to expected argument type
'dispatch_block_t' (aka '#convention(block) () -> ()')
What am I not understanding ?
With writing this sort of expression:
SKAction.runBlock(myFunc(tile))
You are passing the result of calling myFunc(tile).
(I believe you do not think this code: SKAction.runBlock(sin(0)), would pass some sort of closure to runBlock.)
And the returned value from myFunc(tile) is a void value, as myFunc is declared to return nothing. A void value can be represented also as (). The error message says () cannot be converted to a closure of type #convention(block) () -> ().
Thus, you need to create a closure of type #convention(block) () -> ().
tile.runAction(SKAction.runBlock({()->() in myFunc(tile)}))
in short:
tile.runAction(SKAction.runBlock({myFunc(tile)}))
You are missing {} Just:
tile.runAction(SKAction.runBlock({
myFunc(tile)}))