Swift: Issue with closure arguments - swift

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
}

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

How do I write the not/negate higher order function in swift?

I am a Javascripter and I love using the not/negate function:
function not (predicateFunc) {
return function () {
return !predicateFunc.apply(this, arguments);
};
}
I am trying to do the same thing with swift:
func not <A> (_ f: #escaping (_ A: Any) -> Bool) -> (A) -> Bool {
return { a in !f(a) }
}
But I am getting errors like
generic parameter 'T' could not be inferred
and
Cannot convert value of type '(_) -> Bool' to expected argument type '(Any) -> Bool'
The outcome I am looking for is when I have a function like this:
func isEmpty<T: Collection>(collection: T) -> Bool {
return collection.count == 0
}
I can just create a notEmpty function like this:
let notEmpty = not(isEmpty)
And then use it like
notEmpty([3,4,5]) // true
What am I doing wrong?
Using Any is a code smell. You can just extend Collection directly:
extension Collection {
var notEmpty: Bool {
return !isEmpty
}
}
[1, 3, 5].notEmpty // true
Your functional definition of not can work like this:
func not <A> (_ f: #escaping (_ a: A) -> Bool) -> (A) -> Bool {
return { a in !f(a) }
}
But to call it you would need something like this:
let arrayNotEmpty = not { (array: [Int]) in array.isEmpty }
arrayNotEmpty([1, 3, 5]) // true
You have two errors:
You're using A as both the type parameter and as the argument name.
You're using Any as the argument type instead of using the type parameter (A) as the argument type.
Try this:
func not<A>(predicate: #escaping (A) -> Bool) -> (A) -> Bool {
return { !predicate($0) }
}
Note that in this version, I'm not using argument names for the predicate argument. You don't need an argument name in the declaration ((A) -> Bool) and I'm using the anonymous argument name ($0) in the body.
Okay, so you want to write this:
func isEmpty<T: Collection>(collection: T) -> Bool {
return collection.count == 0
}
func not<A>(_ predicate: #escaping (A) -> Bool) -> (A) -> Bool {
return { !predicate($0) }
}
let notEmpty = not(isEmpty)
And you get this error:
let notEmpty = not(isEmpty)
^ Generic parameter 'A' could not be inferred
The problem is that this code tries to create a generic closure, but Swift doesn't support generic closures.
That is to say, what would the type of nonEmpty be? It would be something like:
<A: Collection>(A) -> Bool
and Swift doesn't support that.

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...

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