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)}))
Related
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\"")
}
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
This code is from this blog.
Is the reason we can call completion() because the closure that's passed in () -> () is essentially assigned to the parameter completion and so calling completion executes the closure?
func thisNeedsToFinishBeforeWeCanDoTheNextStep(completion: () -> ()) {
print("The quick brown fox")
completion()
}
func thisFunctionNeedsToExecuteSecond() {
print("jumped over the lazy dog")
}
If that's the case re: calling the function below I don't quite get how the code below translates into the first function being called and completed before the thisFunctionNeedsToExecuteSecond() is? What I mean by that is how is the ()->() in resulting in the completion() executing before thisFunctionNeedsToExecuteSecond() is called - it's hard explaining this in writing.
thisNeedsToFinishBeforeWeCanDoTheNextStep { () -> () in
thisFunctionNeedsToExecuteSecond()
}
If you create a function with a closure as one of its input parameters, the closure is executed as soon as you call it by inputParameterName(). The parentheses after the name of the input parameter mark the function call with no input parameters to the closure, since its type in your case is Void->Void.
In your second example,
thisNeedsToFinishBeforeWeCanDoTheNextStep { () -> () in
thisFunctionNeedsToExecuteSecond()
}
you see a trailing closure. If the last input parameter of a function is a closure, the function call can be converted to the trailing closure syntax, where you can omit the name of the closure (completion in your case) and the code between the {} will be executed once the closure is called.
So the above code is equivalent to
thisNeedsToFinishBeforeWeCanDoTheNextStep(completion: { () -> () in
thisFunctionNeedsToExecuteSecond()
})
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.
I have a method that contains an block which defined in Objective - C:
+(void)getNewList:(NewListRequestModel *)model returnInfo:(void(^)(NewListResponseModel* resModel))retModel;
and I invoke it like:
[API getNewList:model returnInfo:^(NewListResponseModel *resModel) {
//code
}];
in Objective - C .
Now I want invoke it in Swift 3.2 :
API.getNewList(model, returnInfo: {(resModel: NewListResponseModel) -> () in
//my code
})
but I always got an error:
Cannot convert value of type '(NewListResponseModel) -> Void' to expected argument type '((NewListResponseModel?) -> Void)!'
can some one help me the right way to invoke it? thanks.
In Swift, closures can be very easily written. The compiler infers the parameter types and return type for you, so all you need to do is write the parameter name and in:
API.getNewList(model, returnInfo: {resModel in
//my code
})
You can also use the trailing closure syntax:
API.getNewList(model) {resModel in
//my code
}
The error occurs because resModel actually is of an optional type. iN the original Objective-C code, resModel was a pointer, which can be null. When this is bridged to swift, it turns into NewListResponseModel?.
Try this:
class func getNewList(model: NewListResponseModel
returnInfo: ((_ resModel: NewListResponseModel?) -> Void)?){
}
API.getNewList(model, returnInfo: {(resModel) in
//my code
})
//MARK: Class function to pass requestModel and get response model
class func getNewList(model: NewListRequesstModel, completion: #escaping (returnModel: NewListResponseModel) -> Void) {
//Your code to get new model for retrun
}
API.getNewList(model: newModelObject, completion: { (retunModelobject) in
//your code
})