Function with optional completion block in Swift [duplicate] - swift

This question already has answers here:
Can swift closures be set to a default value when used as a parameter in a function?
(4 answers)
Closed 6 years ago.
When I create a function, I can make a parameter optional by giving it a default value, like this:
func foo(bar: String = "foobar") {}
I want to do the same (make it optional) with a completion block. I have tried the following:
func foo(completionBlock: (foo: String) -> () = () -> ())
func foo(completionBlock: (foo: String) -> () = (foo: String) -> ())
func foo(completionBlock: (foo: String) -> () = ((foo: String) -> ()))
func foo(completionBlock: (foo: String) -> () = ((foo: String) in))
func foo(completionBlock: (foo: String) -> () = {(foo: String) in})
How can I do this?
EDIT: This is/was a duplicate question, sorry for that. However, I couldn't find the solution in the original question. So nathan's answer is the best one

If you want to default to nil:
func foo(completionBlock: ((String) -> ())? = nil) {
}
If your default completion block is very simple, you can put it right in the function's definition:
// A default completion block that is simple enough to fit on one line
func foo(completionBlock: (String) -> () = { result in print(result) }) {
// ...
}
// A default completion block that does nothing
func foo(completionBlock: (String) -> () = {} ) {
// ...
}
If your default completion block is more complex, you can define it as a separate function:
func defaultCompletion(result: String) {
// ...
}
func foo(completionBlock: ((String) -> ()) = defaultCompletion) {
}

In Swift 3:
func foo(completionBlock: (String) -> () = { _ in }) {}

Related

Understand swift Dictionary syntax

I work with legacy code and i find following code:
let actions = [PrinterReportType.z: {
printer.printZReport($0)
DeviceFabric.lifehubTerminal().reconciliation()
}, .x: printer.printXReport, .openSession: printer.openSession}]
"Actions" is declared like this:
let actions: [PrinterReportsModel.PrinterReportType : ((String?) -> ()) -> ()]
Key is enum value, but i can't figure out what is value here.
I have new enum type of PrinterReportsModel.PrinterReportType, and i simply want to add new value to that dictionary. I suppose this is some kind of function. So, i want to declare that function, add it here, but i can't figure out how. And i can't figure out wha type is - ((String?) -> ()) -> ()
String is a collection of characters.
String? means the same as Optional<String>, so it is either Optional.none or Optional.some(String).
(String?) -> () is a function that takes a String? and returns nothing (() also called Void, the zero-element tuple). Let's call this as a String?-consumer: it takes a String? and does something with it. Maybe it just throws the String? away. Maybe it prints it. Maybe it stores the String? in a variable or a database or sends it over the network.
You could define a String?-consumer closure like this:
let action: (String?) -> () = { (_ s: String?) -> () in
print(s ?? "(none)")
}
(I'm fully specifying the types above, but you could omit some of the types and let the compiler infer them.)
You could define a String?-consumer function like this:
func test(_ s: String?) -> () { print(s ?? "(none)" }
And pass it around like this:
let action: (String?) -> () = test
You could define a String?-consumer method in a class (or struct) like this:
class MyObject {
func test(_ s: String?) -> () { print(s ?? "(none)") }
}
And pass it around like this:
let myObject = MyObject()
let action: (String?) -> () = myObject.test
((String?) -> ()) -> () is a function that takes a String?-consumer and returns nothing. You can think of this as a String?-consumer-consumer. Maybe it throws the String?-consumer away. Maybe it stores the String?-consumer in a variable for later. Maybe it calls the String?-consumer once, or ten times, or once for each element in some array of strings. Maybe it schedules a call to the String?-consumer every second until the program exits.
You could define a String?-consumer-consumer closure like this:
let action: ((String?) -> ()) -> () = { (_ sc: (String?) -> ()) -> () in
sc("hello")
sc(nil)
sc("world")
}
You could call the closure like this:
action({ (_ s: String?) -> () in print(s ?? "(none)")}
Or like this:
let printString: (String?) -> () = { print($0) }
action(printString)
You could define a String?-consumer-consumer function like this:
func test(_ sc: (String?) -> ()) -> () {
sc("hello")
sc(nil)
sc("world")
}
And pass it around like this:
let action: ((String?) -> ()) -> () = test
You could define a String?-consumer-consumer method in a class (or struct) like this:
class MyObject {
func test(_ sc: (String?) -> ()) -> () {
sc("hello")
sc(nil)
sc("world")
}
}
And pass it around like this:
let myObject = MyObject()
let action: ((String?) -> ()) -> () = myObject.test

Given the same callback implementation, abstract function calls

Assuming I have 2 functions foo and bar defined below.
func foo(completion: #escaping (Response) -> Void)
func bar(a: Int, completion: #escaping (Response) -> Void)
Then I have 2 different functions that use foo and bar
func doSomethingWithFoo() {
foo { response in
handleResponse(response)
}
}
func doSomethingWithBar() {
bar(a: 42) { response in
handleResponse(response)
}
}
doSomethingWithFoo and doSomethingWithBar are very similar. They do the exact same thing with response they get in the completion callback.
My question is: is there a way in Swift to generalize doSomethingWithFoo and doSomethingWithBar? Maybe something in line with the following.
func doSomething(<???>) {
<???> { response in
handleResponse(response)
}
}
<???> is a placeholder for passing either foo or bar or even any other function that also accepts a callback of type (Response) -> Void.
I'll appreciate any help/insights. Thanks.
You can declare a function like this :
func doSomething(fooBar: (_ completion: #escaping (String) -> Void) -> Void) -> Void {
fooBar(handleResponse)
}
Which you would call like this:
doSomething(fooBar: { bar(a: 42, completion: $0) })
doSomething(fooBar: foo)

Pass a closure in a function

I have a little experience in Swift and facing a problem to pass a closure in a function as a parameter.
//1.
public func changeMyStatus(to f:?, _ completion:#escaping (_ isSucced:Bool)->()){
//
}
//2.
func goLive(_ completion:#escaping (_ isSucced:Bool)->()){
}
//3.
func goNonLive(_ completion:#escaping (_ isSucced:Bool)->()){
}
Now , I want to use first function in my controller and wants to pass second/third function as a parameter. Closure in first will return true/false depending on what returned by closure in second/third.
i)What will be the type I should put in first function?
Also I want to call first function from my class like this
changeMyStatus(to: goNonLive) { (isSuccess) in
}
please help
You need to change the changeMyStatus function signature and implementation like:
public func changeMyStatus(to f: (#escaping (Bool) -> ()) -> () , _ completion:#escaping (_ isSucced:Bool)->()){
f { (status) in
completion(status)
}
}
You can call these function like:
// goLive
changeMyStatus(to: goLive(_:)) { (status) in
print(status)
}
// goNonLive
changeMyStatus(to: goNonLive(_:)) { (status) in
print(status)
}
Your second and third function has a completion parameter with a type of : (Bool -> Void) -> Void
So in order to pass it to your first function, try this way :
public func changeMyStatus(to f: ((Bool) -> ()), _ completion:#escaping (_ isSucced:Bool)->()) { // Your body}
In Swift, you need to see a function as a type like Int, Double, String...

Swift: Issue with closure arguments

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
}

passing a function along with an inout parameter

the constructor is receiving two parameters.
a) a function whose type is a function receiving an inout params (so it can change the params)
b) passing your params object, expecting the function passed will be able to modify the object
then trigger the apply method, so your passed function can change the passed params.
If there's a solution with passing params in a closure, that'd work too.
class Test {
var params: Any?
var myFunc: (inout params: Any?) -> () = { (inout params: Any?) in return } //default value
//constructor receving a function and a address to inout params object
init(myFunc: (inout params: Any?) -> (), inout params: Any?) {
self.myFunc = myFunc
self.params = params
}
//call the passed function (extern) and pass the address of given params
func apply() {
self.myFunc(params: &self.params)
}
}
func extern(inout params: Any?) {
var a = params as [String: Int]
a["factor"] = 11
}
var p: Any = ["factor": 10]
var test = Test(myFunc: extern, params: &p)
test.apply() //p["factor"] should be 11 now here
p["factor"] as [String: Int]
My second attempt using closures
//Utility
class Test {
var closure: () -> Any
var myFunc: (message: String, closure: () -> Any) -> () = { (message: String, closure: () -> Any) in return }
init(myFunc: (message: String, closure: () -> Any) -> (), closure: () -> Any) {
self.myFunc = myFunc
self.closure = closure
}
func apply(message: String) {
self.myFunc(message: message, closure: self.closure)
}
}
//users of the utility
func extern(message: String, closure: () -> Any) {
println(message)
var name = closure() as [String: String]
name["name"] = "Doe"
}
var name: Any = ["name": "John"]
var test = Test(myFunc: extern, closure: {name})
test.apply("hello ")
name //it's still John here
3rd attempt using AnyObject and closures and of course it works but still need your opinion guys for a best strategy.
//Utility
class Test {
var closure: () -> AnyObject
var myFunc: (message: String, closure: () -> AnyObject) -> () = { (message: String, closure: () -> AnyObject) in return }
init(myFunc: (message: String, closure: () -> AnyObject) -> (), closure: () -> AnyObject) {
self.myFunc = myFunc
self.closure = closure
}
func apply(message: String) {
self.myFunc(message: message, closure: self.closure)
}
}
//users of the utility
func extern(message: String, closure: () -> AnyObject) {
println(message)
var name: Name = closure() as Name
name.name = "Doe"
}
class Name {
var name = "John"
}
var name = Name()
var test = Test(myFunc: extern, closure: {name})
test.apply("hello ")
name //it's changed here
It seems like you're trying to reinvent closures here. One point of closures is that they can capture references to the values around them. This should do what you're describing above, and lets you keep using proper types for your variables, rather than falling back on Any:
class Test {
var myFunc: () -> Void = { }
init(myFunc: () -> Void) {
self.myFunc = myFunc
}
func apply() {
self.myFunc()
}
}
func extern(inout dict: [String: Int]) {
dict["factor"] = 11
}
var p = ["factor": 10]
let test = Test {
extern(&p)
}
test.apply() // p["factor"] is now 11 here
println(p)
// ["factor": 11]