Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift Passing Closure With Params

Currently I'm passing in a closure as a property on an object that accepts no params and has no return value as follows:

class MyClass {
    var myClosureProperty: (() -> ())? {
            didSet {
                doSomeActionWhenClosureIsSet()
            }
    }
}

var instanceOfMyClass = MyClass()
instanceOfMyClass.myClosureProperty = {
    // do some things here...
}

and so far this is working great. I want to be able to pass in a parameter when setting this closure to be used inside the instance of MyClass. I'm looking for SOMETHING like below, although the syntax I'm sure is incorrect:

class MyClass {
    var myClosureProperty: ((newString: String) -> ())? {
            didSet {
                doSomeActionWhenClosureIsSet(newString)
            }
    }

    func doSomeActionWhenClosureIsSet(stringParam: String) -> () {
        // create a button with the stringParam title...
    }
}

var instanceOfMyClass = MyClass()
instanceOfMyClass.myClosureProperty = {("Action")
    exampleFunction()
}

How would I go about passing in a parameter to this closure that can be used inside of MyClass - i.e. a value that can be used inside the didSet portion of the property itself as in the second example?

EDIT: Here's what ended up working for me:

class MyClass {
        var myClosurePropertyWithStringAndAction: (buttonName: String, closure: (() -> ()))? {
            didSet {
                  let buttonTitle = myClosurePropertyWithStringAndAction!.buttonName
                  createButtonWithButtonTitle(buttonTitle)
            }
         }

        func createButtonWithButtonTitle(buttonTitle: String) -> () {
             // here I create a button with the buttonTitle as the title and set
             // handleButtonPressed as the action on the button
        }

        func handleButtonPressed() {
            self.myClosurePropertyWithStringAndAction?.closure()
        }
    }
}

And here is how I call it on the instance:

instaceOfMyClass.myClosurePropertyWithStringAndAction = ("Done", {
    // do whatever I need to here
})
like image 547
Mike Avatar asked Jun 13 '14 14:06

Mike


1 Answers

Since you are trying to set pass 2 things, a closure AND a button name, you won't be able to do that with a simple setter to the closure.

The constraint you have is that these 2 things are dependent on each other, so you must either set both or none.

First of all, adding newString to your closure isn't doing what you think it does. Its a parameter so you can pass a string to your closure when you call it, it isn't a way to pass in a string when you define the closure.

A "Swift way" to do what you want might be to define it as a tuple. You can name the values inside a tuple so it would work how you want it. Try it like this:

class MyClass {
    var stringAndClosure: (buttonName: String,closure: (() -> ()))? {
        didSet {
            //create button named buttonName
            let name = stringAndClosure!.buttonName
        }
    }
}

let instanceOfMyClass = MyClass()
instanceOfMyClass.stringAndClosure =  ("Action",{ exampleFunction() })
like image 51
Jack Avatar answered Oct 14 '22 09:10

Jack