Search code examples
swiftclosuresblock

How to create generic closures in Swift


I would like to create a function that uses generic closure (block) in swift.

My first attempt was to do like :

func saveWithCompletionObject(obj : AnyObject, success : AnyObject -> Void, failure : Void -> Void)

But as soon as I call this function with another block, such as :

func doSomething(success : String -> Void, failure : Void -> Void)
{
    saveWithCompletionObject("Example", success, failure)
}

I get an error : 'AnyObject' is not a subtype of 'String'

Thanks in advance !


Solution

  • You cannot pass a closure of type String->Void to a parameter of type AnyObject->Void.

    However, you can define a generic function:

    func saveWithCompletionObject<T>(obj : T, success : T -> Void, failure : Void -> Void) {
        // ...
        success(obj)
    }
    

    Now the compiler can verify that obj has the same type as the parameter of success, for example:

    func doSomething(success : String -> Void, failure : Void -> Void)
    {
        saveWithCompletionObject("Example", success, failure)
    }
    
    func doSomethingElse(success : Int -> Void, failure : Void -> Void)
    {
        saveWithCompletionObject(13, success, failure)
    }
    

    But I would recommend that saveWithCompletionObject just takes a Void->Void parameter (without generics):

    func saveWithCompletionObject(success : Void -> Void, failure : Void -> Void) {
        // ...
        success()
    }
    

    and the caller wraps its closure:

    func doSomething(success : String -> Void, failure : Void -> Void)
    {
        saveWithCompletionObject( { success("Example") } , failure)
    }
    
    func doSomethingElse(success : Int -> Void, failure : Void -> Void)
    {
        saveWithCompletionObject( { success(13) }, failure)
    }
    

    This is more flexible, e.g. for callback functions with more than one parameter:

    func andNowForSomethingCompletelyDifferent(success : (Int, Double) -> Void, failure : Void -> Void)
    {
        saveWithCompletionObject( { success(13, M_PI) }, failure)
    }