how to pass a callback function in another function in swift? - swift

so i'm doing my first app,
and i want to do a function that will be a uniform funciton to sevral places in the system, and not belong to only one specific class.
Is there a way for me to pass a callback function as a parameter to another function ?
here is just a demonstration of what i mean.
ClassA {
func classAcallbackFunction (displayString: String) {
print (displayString)
}
ClassB().classBFunction(classAcallbackFunction())
}
ClassB {
func classBfunction (myCallbackfunc: func) {
mycallbackfunc("all is working !!!")
}
}

The parameter you have declared is not correct. Replace it with something like this:
func classBFunction(_ completion: (String) -> Void) {
completion("all working")
}
Like shared by regina_fallangi in the comments, callbacks are usually called completion handlers, which is why I replaced the names accordingly.
Extra Credit:
If you only want to optionally pass a function, you could do this:
func classBFunction(_ completion: ((String) -> Void)? = nil) {
completion?("all working")
}
Now you could also just call classBFunction().

Related

What's the difference between the two closure

I tried comment and uncomment the activity() in the following code. I found when I commented the activity() the result in playground would just show "play tennis" once. However it would show twice if I uncommented activity(). What's the difference between the two statements?
class Baby {
var name = "peter"
var favoriteActivity: (() -> ())!
func outsideActivity(activity: #escaping () -> ()) {
//activity()
favoriteActivity = activity
}
}
var cuteBaby = Baby()
cuteBaby.outsideActivity {
print("play tennis")
}
cuteBaby.favoriteActivity()
This is what’s going on:
Consider this method:
func outsideActivity(activity: #escaping () -> ()) {
//activity()
favoriteActivity = activity
}
All that does is save the closure in the favoriteActivity property
Thus, when you do:
// create `Baby` instance
var cuteBaby = Baby()
// this method saves closure in `favoriteActivity`, but doesn’t call it
cuteBaby.outsideActivity {
print("play tennis")
}
// this now calls the closure
cuteBaby.favoriteActivity()
All the outsideActivity method does is save the closure in a property called favoriteActivity.
Thus you see one print statement.
However, now consider this method:
func outsideActivity(activity: #escaping () -> ()) {
activity()
favoriteActivity = activity
}
This actually calls the closure before saving it in the property.
So, when you do:
// create `Baby` instance
var cuteBaby = Baby()
// this method both calls the closure and then also saves it in `favoriteActivity`
cuteBaby.outsideActivity {
print("play tennis")
}
// this now calls the saved closure a second time
cuteBaby.favoriteActivity()
In this case, you’ll see your print statement being called twice.
That’s why the first rendition calls the closure only once, whereas the second calls the closure twice.
Usually when you pass a closure to a method, you either (a) call the closure from within the method (perhaps in some completion handler or the like); or (b) save the closure in some property so you can call it later.
So, this second example is very unusual, where outsideActivity both calls the closure itself and saves that closure in some property so you can call it again later. You usually do one or the other, but not both.

Why assign void to local variable

So this is actually possible.
func clearItems() {
}
func reloadItems(_ clearItems: (() -> Void)? = nil) {
if let void = clearItems?() {
}
}
reloadItems(clearItems)
Should this be illegal? Or should we be forced to use _ intead of a variable name? Can void actually be consumed in some way here?
Void is a type in Swift just like anything else. There's seldom need to pass it around, but that doesn't change the fact the language supports returning and storing it in constants.
This implicitly happens anyway, you're just being explicit. You can, if you want return () at the end of every function that doesn't return a value since () represents an instance of Void. The compiler does that for you though so you don't need to.
Yes, but you need to change your reloadItems method to look like this:
func reloadItems(_ clearItems: (() -> Void)? = nil) {
if let void = clearItems {
void() // Call void.
}
}
by saying clearItems?(), you are calling the passed function, which is not the thing you wanted to do. You wanted to safely unwrap the passed function, so you need to treat it as a passed variable like the above snippet.
If you didn't use the if let statement, you can call clearItems like this:
clearItems?()
This will call the passed function if it isn't nil, and will do nothing if it is nil.
So your reloadItems function can simply become like this:
func reloadItems(_ clearItems: (() -> Void)? = nil) {
clearItems?() // This will call the passed function if it isn't nil, and will do nothing if it is nil.
}

Calling a function from 'text' in swift

I'm writing some generic code, so all view controllers can use it.
One of the things I like to make generic is an alert function.
The problem here is that I must code the actions in the replies.
That's fine with warnings (only press OK), or generic responses (Cancel, No), but when a (generic) function needs to run, I need to trick to pass on which function.
If I can run a function from some text, it will reduce the problem (and I don't have to hard-code all the functions that can be called).
Or is there a much better way of achieving my 'generic' alert?
Sample here:
func DoAlert(title: String, message: String, actions: String, sender: AnyObject, viewController : UIViewController) {.......
.....
if (actions as NSString).containsString("Yes") {
alert.addAction(UIAlertAction(title: "Yes", style: .Default) { action -> Void in
if (actions as NSString).containsString("Yes'DoAfunction()'") {
DoAfunction() }
})}
.....
}
// Rather than hard-coding, I like to abstract the function between ' ' and use that to call the function
// I call the function as follows:
DoAlert("Warning", alertText, "Yes'DoAfunction()'No", sender, self)
/////////// SOLUTION: ////////////////
Following Bluehound's suggestion to use closures, I ended up adding optional closures for different responses.
For those wishing to do same, below is my solution:
Solution here:
func DoAlert(title: String, message: String, actions: String, sender: AnyObject, viewController : UIViewController, YesClosure: ()->() = {}, NoClosure: ()->() = {}) {.......
.....
if (actions as NSString).containsString("Yes") {
alert.addAction(UIAlertAction(title: "Yes", style: .Default) { action -> Void in
YesClosure() // This will the run the function if provided
})}
.....
}
// I call the function as follows:
DoAlert("Warning", alertText, "YesNo", sender, self, YesClosure: DoYesFunction, NoClosure: DoNoFunction)
If there is nu function to be performed, leave the option out. (below only has function for NO)
DoAlert("Warning", alertText, "YesNo", sender, self, NoClosure: DoNoFunction)
Instead of passing the name of a function to complete, you can pass a closure as a parameter and when calling the function, you define what goes function is passed in. For example:
func foo(closure: () -> Void) {
closure()
}
foo {
println("Some text")
} // prints Some Text
Now for using multiple actions you can pass an array of closures like so:
func foo(closures: [() -> Void]) {
for closure in closures {
closure()
}
}
foo([{println("a")},
{println("b")},
{println("c")}]) // prints a b c

How to define a function with a function type parameter in Swift

I could define a function like this
func doWithAction(action: ()-> void) {
// something
}
However, when I use the function, the auto-completion of Xcode give me a block/closure
self.addPullToRefreshControllerWithAction { () -> void in
}
I know closure and function are something same in Swift, but I want to lead the one who use this function to pass a function in, not a block. The reason why I do this is I want this function to behave like a selector and a delegation
yes, closure and functions are practically the same in swift, so if the function expects a closure, you can pass a function with the same signature as a parameter instead. like this
func iAmAFunc(() -> Void) -> Void {
//do stuff
}
func funcThatTakesVoidAndReturnsVoid() -> Void {
//do stuff
}
var closureThatTakesVoidAndReturnsVoid: () -> Void = { }
iAmAFunc(funcThatTakesVoidAndReturnsVoid)
iAmAFunc(closureThatTakesVoidAndReturnsVoid)

Is there a shorthand for a function that takes no parameters and returns nothing? AKA () -> ()

The title says it all, I believe. I'm simply curious if the () -> () acting as a function's parameter...
class Test {
var isAwesome = true
func loadData (callback: () -> ()) {
callback();
}
}
... has a shorter version. That's it!
I'm not sure if there is a "Swift-way" to do it, but if you really want to shorten it:
typealias A = ()->() // alias this closure risking readability
class Test {
func loadData (callback:A) {
callback();
}
}
It is a bit of a hack I suppose.
As found in: Apple Inc. 'The Swift Programming Language'. iBooks. https://itun.es/nl/jEUH0.l
You can use the following syntax:
func someFunctionThatTakesAClosure(closure: () -> ()) {
// function body goes here
}
// here's how you call this function without using a trailing closure:
someFunctionThatTakesAClosure({
// closure's body goes here
})
// here's how you call this function with a trailing closure instead:
someFunctionThatTakesAClosure() {
// trailing closure's body goes here
}
I cannot find any documentation that specifies a different solution. Every instance I can find in the current docs/book shows it how you have it. Here is a good section that talks about it. You can however call your method with some pretty short notation:
loadData {
// ...
}
Rather than having to treat it as a normal parameter:
loadData({
// ...
})
You can also call it like:
loadData() {
// ...
}
I think there is no shorter-way: I can just imagine a type-alias (like #Benzi mentioned), but the effect seems not worth the hack.
func takeEmptyFunc(emptyFunc: ()->()) { emptyFunc() }
func emptyFunc() { println("Worked"); }
takeEmptyFunc() { emptyFunc() } // prints "Worked"