I'm diving into Swift lang by Apple and have some problems using the trailing closure syntax, example:
func test(txt: String, resolve: (name: String) -> Void) {
resolve(name: "Dodo")
}
// Errors here complaining on resolve param
test("hello", (name: String) {
println("callback")
})
How to fix it?
you have the wrong closure syntax
test("hello", {(name: String) in
println("callback")
})
or
test("hello", {
println("callback: \($0)")
})
or
test("hello") {(name: String) in
println("callback")
}
or
test("hello") {
println("callback: \($0)")
}
Related
I found a behaviour in Swift's type resolution that I don't fully understand.
The following example compiles. My understanding is that:
the method implementation is defined by the type of the execute closure
the closure type is defined by its parameter arg in the call to call8 (UInt8) or call16 (UInt16) in the body of the closure.
I appreciate this feels a bit like pushing the boundaries of what the type system should be doing but I was happy to see it working properly:
func call8(_ arg: UInt8) { print("8")}
func call16(_ arg: UInt16) { print("16")}
struct Instruction {
func method(name: String, execute: #escaping ((String, UInt8) -> Void)) {
print ("1", terminator:", ")
execute(name, 8)
}
func method(name: String, execute: #escaping ((String, UInt16) -> Void)) {
print ("2", terminator:", ")
execute(name, 16)
}
}
let i = Instruction()
i.method(name: "test", execute: { string, arg in call8(arg)}) // prints 1, 8
i.method(name: "test", execute: { string, arg in call16(arg)}) // prints 2, 16
The following example is the same as the one before, except that the execute closure returns a value.
Now, to my surprise, this doesn't compile anymore.
func call8(_ arg: UInt8) { print("8")}
func call16(_ arg: UInt16) { print("16")}
struct Instruction {
func method(name: String, execute: #escaping ((String, UInt8) -> Int)) {
print ("1", terminator:", ")
_ = execute(name, 8)
}
func method(name: String, execute: #escaping ((String, UInt16) -> Int)) {
print ("2", terminator:", ")
_ = execute(name, 16)
}
}
let i = Instruction()
// These both give an error: "Ambiguous use of 'method(name:execute:)"
i.method(name: "test", execute: { string, arg in call8(arg); return 1})
i.method(name: "test", execute: { string, arg in call16(arg); return 1})
Can anybody please explain me why?
You are misunderstanding what's happening. It's not about returning a value. Simplify, for a clearer demonstration of that:
func call8(_: UInt8) -> String { "8" }
func call16(_: UInt16) -> String { "16" }
func ƒ(_ call: (UInt8) -> String) { call(8) }
func ƒ(_ call: (UInt16) -> String) { call(16) }
ƒ(call8) // "8"
ƒ(call16) // "16"
Instead, it's all about multiple lines. Read all about it!
https://forums.swift.org/t/multiline-closure-is-not-inferring-the-return-type/40013
As for the fix, you've got to explicitly type, for disambiguation. 😫
(string, arg: UInt8)
(string, arg: UInt16)
Here a function b calls a and passes a completion block:
func a(completion: (_ succeeded: Bool)) {
completion(true)
}
func b() {
a() { succeeded in
...
}
}
Can I use a protocol function definition to define the block?
Something like this (which does not work):
protocol P {
func c(succeeded: Bool)
}
func a(completion: P) {
completion.c(succeeded: true)
}
func b() {
a() { c(succeeded) in
...
}
}
Note: I am not looking for the protocol/delegate concept.
The issue with using a protocol here is that functions cannot conform to a protocol, only classes, enums and structs can conform to a protocol. So you either need one of these types or an instance of one of these types, but then the instance seems superfluous. If you really want to do it the protocol way here is an example with static conformance on an enum:
import UIKit
protocol Callable {
static func call(someString: String, someInt: Int)
}
enum MyCallable: Callable {
static func call(someString: String, someInt: Int) {
print(someString, someInt)
}
}
func someFunction<T: Callable>(callable: T.Type) {
callable.call(someString: "a",someInt: 1)
}
someFunction(callable: MyCallable.self)
You can use a labeled tuple to give yourself argument labels if that is what you are after. Here is a playground example:
import UIKit
typealias MyArguements = (someInt: Int, someString: String)
func someFunction( completion: #escaping (MyArguements) -> Void) {
completion((someInt: 1, someString: "a"))
}
someFunction { tuple in
let (someInt, someString) = tuple
print(someInt, someString)
}
why does the first function call not yield any error while the second function call yields an error? I'm not invoking a function but simply calling it. The difference between the two functions are the number of parameters.
func hello(firstName: String) {
print("Hello \(firstName)")
}
hello(firstName:)
func hello(firstName: String, lastName: String) {
print("Hello \(firstName) \(lastName)")
}
hello(firstName:, lastName:)
The Swift Book does not contain a easy-to-read description, but your first code is a valid expression in Swift, which returns a closure of type (String)->Void:
func hello(firstName: String) {
print("Hello \(firstName)")
}
var closure: (String)->Void = hello(firstName:)
closure("Taro") //->Hello Taro
In your second code, hello(firstName:, lastName:) is not a valid expression in Swift, but hello(firstName: lastName:) is valid:
func hello(firstName: String, lastName: String) {
print("Hello \(firstName) \(lastName)")
}
//hello(firstName:, lastName:) //<-invalid
var closure2: (String, String)->Void = hello(firstName: lastName:)
closure2("Taro", "Yamada") //->Hello Taro Yamada
Maybe you have ever seen this sort of notations inside #selector(), but such notations can be used also outside #selector() as shown above.
Here is a function:
func foo(completion: (jsonData: String) -> ()) {
}
In Swift 3, you can't have argument labels. Therefore, this is the code:
func foo(completion: (String) -> ()) {
}
The issue with this, is that when I call the function it looks like this:
foo(completion: { _ in
})
So, if I want to see the value of jsonData, I can't because it's an underscore. How would I solve this issue?
It's working:
func foo(completion: (String) -> ()) {
completion("Hi")
}
foo { jsonData in
print(jsonData) // Output: Hi
}
Recently I'm on a project that requires a lot of APIs Async interacting with the Server, I've tried delegating, but writing a lot of delegator is not very elegant. I've been following all the 'Swift Callback' threads on SO before, Still stucking.
//First try
func post(url: String, data: String, callback:(result: String) ->Void){
callback(result: "Completed")
}
func request(url: String, data: String){
post(url, data, { (result) in
println(result)
})
}
request("Hello", "World")
//prints nothing
//second try following threads
func test(txt: String, resolve: (name: String) -> Void) {
resolve(name: "Dodo")
}
test("hello", {(name: String) in
println(name)
})
What did I missed, Any help will be grateful
Your code looks fine. I run Xcode 7 and needed to make some modifications, but the code worked for me. If you are trying this in Playground, make sure it is actually executing. It often happens to me that I am expecting print statement to show something, but Playground is stuck and does not output anything due to an error.
Here is the code that worked for me (modified for Swift 2):
func post(url: String, data: String, callback:(result: String) ->Void){
callback(result: "Completed")
}
func request(url: String, data: String){
post(url, data: data, callback: { (result) in
print(result)
})
}
request("Hello", data: "World")
func test(txt: String, resolve: (name: String) -> Void) {
resolve(name: "Dodo")
}
test("hello", resolve: {(name: String) in
print(name)
})
If you'd like to run your code in a playground, you need to tell Xcode to not exit (so that it can make the request in background and execute async callbacks).
Appending this to your playground should make it work:
import XCPlayground
XCPSetExecutionShouldContinueIndefinitely()