简体   繁体   中英

How to optionally pass in values to a closure in Swift?

I have the following function which reads some heart rate data and accepts a callback in the form of a closure, as such:

func readHeartRate(callback: ((samples: [HKQuantitySample]?, average: Double?, error: NSError!) -> Void)!){
   // ...
   // ERROR - call the callback with no samples or average
   callback(samples: nil, average: nil, error: error)
})

Right now, I'm explicitly passing back nil for samples and average to the callback.

However, since samples and error are optional, and since I declared the names in the closure explicitly, I thought this would be possible, instead:

callback(error: error)

However, when I do this xcode complains and throws the error:

Missing argument for parameter 'samples' in call

Is there a way to call the callback with only the values necessary to avoid cluttering my code?

From The Swift Programming Language :

Closure expression syntax can use constant parameters, variable parameters, and inout parameters. Default values cannot be provided. Variadic parameters can be used if you name the variadic parameter and place it last in the parameter list.

So only way to be able to call closure with variable number of specified parameters is by using variadic params, which - I assume - is not what you want.

For a regular method, you can provide a default value for a parameter:

func myCallback(#error: NSError!, samples: [HKQuantitySample]? = nil, average: Double? = nil) {
}

myCallback(error: nil)

These parameters with default values should be at the end of the argument list.

This doesn't work in your case, since you're not defining a method; you're just specifying the method signature that callers need to pass in for the callback. You can say "pass in a method that takes an Int ", for example, but there's no way currently to say "pass in a method that takes an Int and uses a default of 0 if I don't pass anything in".

Remember, optional values just mean the existence of a value is optional and the thing can be nil.

I have had occasions where I decided to wrap a closure in a function so that I could provide a default parameter. It works like this:

let myClosure: String -> () = { string in
    println(string)
}

func myFunc(string: String = "default") {
    myClosure(string)
}

myFunc()       // prints "default"

I know that your goal is to "declutter" your code, so whether or not writing wrapper functions is what you want, I don't know, but it works.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM