With Swift 3.1
func foo() {
{ () -> Void in
print("oh, nice, now this works too!!!")
}()
}
foo()
works... but
func foo() {
print("Hi!")
{ () -> Void in
print("oh, nice, now this works too!!!")
}()
}
foo()
Will cause
ERROR at line 2, col 2: cannot invoke 'print' with an argument list
of type '(String, () -> Void)'
That can be fixed inserting semicolon after print
print("Hi!");
or parenthesis around the lambda definition. However, what I'm interested in is what is the root cause of the behaviour from the Swift compiler perspective?
In the second case, you need to separate the print call from the lambda block.
First case:
func foo() { () -> () }
No problem you can do whatever you want in your closure
Second case:
The compiler thinks you're telling the print statement to execute your closure after it ended.
So you need to separate with semicolon your print("hi") statement or wrap the lambda block to be explicit.
Related
Closures As Parameters
let driving = {
print("I'm driving in my car.")
}
func travel(action: () -> Void) {
print("I'm getting ready to go.")
action()
print("I arrived!")
}
travel(action: driving)
action is a parameter label. How come we consider it as a function call as in action()?
Lets look at a brief example:
func myFunction() {...} Swift sees this as () -> Void
the same way that Swift sees this "John" as String
So when you write a function like myFunction you could really say
func myFunction() -> Void {...} for the same result.
Now action is defined as a parameter as a function but the type that it accepts for that parameter is () -> Void aka a closure which for now you can think of just another function.
So the line action() is just the call of that function.
But be sure to read up on functions accepted as parameters
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)}))
I'm using a Swift learning book about extensions with a closure as a parameter.
In the book, it told me
extension Int {
func repeat(work: () -> ()) {
for _ in 0..<self {
work()
}
}
}
On the line
func repeat(work: () -> ()) {
Xcode tells me
Expected identifier in function declaration
and on the line:
for _ in 0..< self {
Xcode tells me
Braced block of statements is an unused closure
and
Expected ‘{’ to start the body of for-each loop
Can anyone can tell me why these errors occur and what should I do?
There are a number of problems with the posted code:
extensionInt should be extension Int, although I suspect this is a typo in you post
As #Zhao Yi pointed out, repeat is a Swift keyword, you need to rename your function (e.g. repeatWork)
The Swift Half-Open Range Operator requires either an empty space on both sides, or no space on both sides. Both these are valid:
0 ..< self
0..<self
Finally, you can call this function like this:
2.repeatWork({
print("Hello")
})
or this:
2.repeatWork {
print("Hola")
}
repeat is a keyword you can't use as a function name. Rename it to something else:
extension Int {
func repeat1(work: () -> ()) {
for _ in 0..<self {
work()
}
}
}
func speak(text:String, onComplete:()->()) {
mySpeechUtterance = AVSpeechUtterance(string: text)
mySpeechSynthesizer.speakUtterance(mySpeechUtterance)
onComplete()
}
My question is: How can I call this method?
speechSynthesizer.speak(actions[0], onComplete: "here")
Pass a closure.
speechSynthesizer.speak(actions.first) {
// code to be executed after speaking
}
This is the same as
speechSynthesizer.speak(actions.first, onComplete: {
// code to be executed after speaking
})
but obviously, the trailing closure syntax looks much cleaner.
Explanation:
the first part () means "a function without arguments",
the second part -> () means "without return value".
There is a number of options. The simplest in this case is considering that onComplete is the last closure the next one:
speechSynthesizer.speak(actions[0]) {
# onComplete code goes here
}
On remark to the function definition in your question. It should probably be
func speak(text:String, onComplete: () -> Void) {...}
Given that I can do closures like this
var test = { () -> String in
return "this works"
}()
I would imagine you could do something like this
func testFunc() {
let _ = "this doesn't work"
}()
But this throws an error - Consecutive statements on a line must be separated by ';'
As far as I recall, swift's funcs are just named closures. Is there a way to make this work?
There are three types of closures in Swift:
Global functions are closures that have a name and do not capture any values.
Nested functions are closures that have a name and can capture values from their enclosing function.
Closure expressions are unnamed closures written in a lightweight syntax that can capture values from their surrounding context.
...
Closure expressions are a way to write inline closures in a brief,
focused syntax.
(Source: Closures in the Swift book.)
In your first example:
var test = { () -> String in return "this works" }()
{ ... } is a closure expression. This expression is evaluated
with an empty argument list (). The result is the string
"this works" which is then assigned to the variable.
Your second example is a global function.
Global functions are (named) closures, but not closure expressions.
There is (as far as I know) no similar way to define a function which
is immediately evaluated.
Because there is no syntax that accepts
func testFunc() {} ()
So it should be
func testFunc() {
let myString = "this works"
}
and called
func myFunc() {
testFunc()
}
func defines a function. If you want to call it you need to do so in a separate statement:
func testFunc() {
let _ = "this doesn't work"
}
testFunc()