Given the same callback implementation, abstract function calls - swift

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)

Related

Swift how to pass closure from one function to another?

Say that I have 2 functions:
functionA(#escaping closureA: ((Double) -> ())) {
// Some Code for function A
}
functionB(#escaping closureB: ((Double) -> ())) {
// Some Code for function B
}
If I want to call functionB from function A, how do I pass function A's closure parameter as argument to functionB's parameter?
Something that looks like this:
func A(#escaping closureA: ((Double) -> ())) {
// Some Code for function A
B(<trying to pass closureA>)
}
func B(#escaping closureB: ((Double) -> ())) {
// Some Code for function B
}
You need to escape the in parameter to the closure to start with and then when calling the closure sent to functionB you need to supply a value as argument
func functionA(closureA: (#escaping (Double) -> ())) {
functionB(closureB: closureA)
}
func functionB( closureB: (#escaping (Double) -> ())) {
closureB(3.2)
}
Example
functionA(closureA: {print($0 * 2.0)})
6.4
Try this example below.
func functionA(closure:(()->Void), completionHandler: #escaping (Double) -> Void) {
closure()
completionHandler(1.0)
}
func functionB(completionHandler: #escaping (Double) -> Void) {
completionHandler(2.0)
}
func nestedClosure() {
functionA(closure: {
functionB { (value) in
print("\(value)")
}
}, completionHandler: { (value) in
print("\(value)")
})
}

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
}

Swift override static method compile error

I have these two swift classes:
class A {
static func list(completion: (_ result:[A]?) -> Void) {
completion (nil)
}
static func get(completion: (_ result:A?) -> Void) {
completion (nil)
}
}
class B: A {
static func list(completion: (_ result:[B]?) -> Void) {
completion (nil)
}
static func get(completion: (_ result:B?) -> Void) {
completion (nil)
}
}
Trying to compile this raise the error "overriding declaration requires an 'override' keyword" but just for the 'get' method of class B. 'list' method compiles fine. What is the difference between [B]? and B? for the compiler in this case?
Edit: Also notice that adding 'override' is not possible. I get the error 'Cannot override static method'.
In class B, the method list is a separate method from list in class A. They just share the same name, that's all.
The parameters of the two list methods are actually different:
// A.list
static func list(completion: (_ result:[A]?) -> Void) {
// B.list
static func list(completion: (_ result:[B]?) -> Void) {
A.list takes an argument of type (_ result: [A]?) -> Void while B.list takes a (_ result: [B]?) -> Void. The array type in the closure type's parameter list is different!
So you're not overridding anything, you're just overloading.
Note:
static methods can never be overridden! If you want to override a method, use class instead of static.
class A {
class func get(completion: (_ result:A?) -> Void) {
completion (nil)
}
}
class B: A {
override class func get(completion: (_ result:B?) -> Void) {
completion (nil)
}
}
In short, as per rule, static methods can't be overridden.

Function with optional completion block in Swift [duplicate]

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 }) {}