28

How can I store an array of functions to callback later in an array like in JavaScript? Any and AnyObject type cannot hold functions with different types of method signatures.

6
  • Without exception handling, I can't think of any use for this. Could you add a little more context to the question for us? Commented Jun 25, 2014 at 21:39
  • Take a look at closures, they're pretty much ideal for things like that. Commented Jun 25, 2014 at 21:48
  • 1
    Array<Void -> Void> or unreadable version (()->())[] Commented Jun 25, 2014 at 22:18
  • My use case is to keep an array of function that I keep passing the result of one function to another. Some of them may take two parameters some may take only one. Commented Jun 27, 2014 at 2:03
  • As of Swift 1.1, Any can hold functions. Commented Oct 17, 2014 at 19:43

5 Answers 5

29

You can use an enum to put various functions into the Array and then extract the functions with a switch.

    enum MyFuncs {
        case Arity0 ( Void -> Void )
        case Arity2 ( (Int, String) -> Void)
    }

    func someFunc(n:Int, S:String) { }
    func boringFunc() {}
    var funcs = Array<MyFuncs>()
    funcs.append(MyFuncs.Arity0(boringFunc))
    funcs.append( MyFuncs.Arity2(someFunc))

    for f in funcs {
        switch f {
        case let .Arity0(f):
            f()  // call the function with no arguments
        case let .Arity2(f):
            f(2,"fred") // call the function with two args
        }
    }
Sign up to request clarification or add additional context in comments.

4 Comments

I logged in just to upvote this answer. This idea looks awesome, provided that you can at compile time write all the possible combinations of function types on the enum.
Odd, it works for me in a playground at global scope, but not if I use inside a class.
Ahh, it does work. I need to move some of the lines to a routine. Never mind. Many thanks for the neat code.
What if boringFunc can throw? Then that won't work anymore
8

Note: this answer is for Swift versions 1.0 and lower.

Functions that have different parameters and return types are of a different type so they can't be stored in an array together. They also don't conform to the Any or AnyObject protocols.

If you have functions with the same parameters though you can work around that. Even though the functions below return a tuple of Double and an Int, they can both be defined as () -> Any function types.

func func1 () -> Int {
    return 1
}
func func2 () -> (Double, Double){
    return (2, 3)
}
var a: () -> Int = func1
var b: () -> (Double, Double) = func2

var arr: Array< () -> Any> = [a, b]

5 Comments

Lets say I want to take one function with two parameters as input and one with only one parameter. This doesn't work then.
Yeah. There is no solution. This is just a workaround that works in a specific case
@EncorePTL, the scenario you are highlighted just won't work in practice, even if you'd be keen to store method with various parameter list, that is practically a useless array of methods.
I can always invoke functions as such function(reinterpretCast(args)) where args is an array which gets converted to appropriate parameters in the function
I want to store functions so I can lazily evaluate the values in the end.
7

Below is an example with both an array and a dictionary. Tested and working in Xcode 6.1 (6A1046a). Note that functions from dictionaries must first be unwrapped.

This technique does however fall apart when the functions have different parameter or return types, for the reasons explained by connor in his answer.

class MyViewController: UIViewController
{
    let arrayOfFunctions = [function1, function2]

    let dictionaryOfFunctions = [
        "function1": function1,
        "function2": function2
    ]

    func function1() {
        NSLog("function1")
    }

    func function2() {
        NSLog("function2")
    }

    override func viewDidLoad()
    {
        let fn1 = arrayOfFunctions[0]
        fn1(self)()

        let fn2 = dictionaryOfFunctions["function2"]
        fn2!(self)()
    }
}

1 Comment

works on xcode 9.2 and swift 3.2. Used it like var actions = [add, massText] if condition { actions.insert(massMsg, at: 1) } call by actions[selectedIndex]()
3

As of Swift 1.1, all function types conform to Any, so you can hold functions in an Any array.

func foo (str: String) -> Int {
    return 1
}
func bar () -> (Double, Double){
    return (2, 3)
}
var a: Any = foo
var b: Any = bar

var arr: Any = [a, b]

1 Comment

And how can you call them then?
1

A simpler approach to call stored function in array on demand , to use parameters a simple workaround is to make dict args and use it inside the function.

var args = [ "a" :  1, "b" : 2 ]
var requestQueue : [() -> Void] = []

func a() -> Void  {
    let param = args["a"]
    print(param!)
}

func b() -> Void {
    let param = args["b"]
    print(param!)
}

requestQueue.append(a)
requestQueue.append(b)

for item in requestQueue {
    item() //calling the functions
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.