Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass closure with argument as argument and execute it?

Initializer of class A takes an optional closure as argument:

class A {
   var closure: ()?

   init(closure: closure()?) {
      self.closure = closure
      self.closure()
   }
}

I want to pass a function with an argument as the closure:

class B {
    let a = A(closure: action(1)) // This throws the error: Cannot convert value of type '()' to expected argument type '(() -> Void)?'

    func action(_ i: Int) {
       //...
    }
}

Class A should execute the closure action with argument i.

I am not sure about how to write this correctly, see error in code comment above. What has to be changed?

like image 464
Manuel Avatar asked Jul 12 '16 20:07

Manuel


People also ask

How do you pass arguments to closure?

A closure is said to escape a function when the closure is passed as an argument to the function, but is called after the function returns. When you declare a function that takes a closure as one of its parameters, you can write @escaping before the parameter's type to indicate that the closure is allowed to escape.

How do you pass an argument in Swift?

If a function takes another function as an argument in Swift, you do not need to specify a separate function and pass that as an argument. Instead, you can use a closure function. A closure is an anonymous function. It is a block of code that acts as a function but does not have a name.

What is $0 and $1 in Swift?

$0 and $1 are closure's first and second Shorthand Argument Names (SAN for short) or implicit parameter names, if you like. The shorthand argument names are automatically provided by Swift. The first argument is referenced by $0 , the second argument is referenced by $1 , the third one by $2 , and so on.

Can we pass function as a parameter in Swift?

Every function in Swift has a type, consisting of the function's parameter types and return type. You can use this type like any other type in Swift, which makes it easy to pass functions as parameters to other functions, and to return functions from functions.


3 Answers

Please make your "what-you-have-now" code error free.

Assuming your class A like this:

class A {
    typealias ClosureType = ()->Void

    var closure: ClosureType?

    init(closure: ClosureType?) {
        self.closure = closure
        //`closure` would be used later.
    }

    //To use the closure in class A
    func someMethod() {
        //call the closure
        self.closure?()
    }
}

With A given above, you need to rewrite your class B as:

class B {
    private(set) var a: A!
    init() {
        //initialize all instance properties till here
        a = A(closure: {[weak self] in self?.action(1)})
    }

    func action(i: Int) {
        //...
    }
}
like image 62
OOPer Avatar answered Sep 28 '22 11:09

OOPer


The problem is that closure()? is not a type. And ()? is a type, but it is probably not the type you want.

If you want var closure to have as its value a certain kind of function, you need to use the type of that function in the declaration, e.g.

var closure: (Int) -> Void

Similarly, if you want init(closure:) to take as its parameter a certain kind of function, you need to use the type of that function in the declaration, e.g.

init(closure: (Int) -> Void) {
like image 34
matt Avatar answered Sep 28 '22 12:09

matt


Types as Parameters

In Swift, every object has a type. For example, Int, String, etc. are likely all types you are extremely familiar with.

So when you declare a function, the explicit type (or sometimes protocols) of any parameters should be specified.

func swallowInt(number: Int) {}

Compound Types

Swift also has a concept of compound types. One example of this is Tuples. A Tuple is just a collection of other types.

let httpStatusCode: (Int, String) = (404, "Not Found")

A function could easily take a tuple as its argument:

func swallowStatusCode(statusCode: (Int, String)) {}

Another compound type is the function type. A function type consists of a tuple of parameters and a return type. So the swallowInt function from above would have the following function type: (Int) -> Void. Similarly, a function taking in an Int and a String and returning a Bool would have the following type: (Int, String) -> Bool.

Function Types As Parameters

So we can use these concepts to re-write function A:

class A {
    var closure: (() -> Void)?

    init(closure: (() -> Void)?) {
        self.closure = closure
        self.closure()
    }
}

Passing an argument would then just be:

func foo(closure: (Int) -> Void) {
    // Execute the closure
    closure(1)
}
like image 44
Matthew Seaman Avatar answered Sep 28 '22 13:09

Matthew Seaman