My function has this signature:
func foo(bar: String, baz: ((String) -> ())? = nil)
And now I want to make unecessary to escape self inside the given closure.
But when I try this:
func foo(bar: String, #noescape baz: ((String) -> ())? = nil)
The compiler complains:
#noescape may only be applied to parameters of function type
Is it possible to use it in optional parameters?
Requirements
If your requirements are the following:
the baz param is a closure
the baz param is marked with #noescape (because you want to omit self in the closure code)
the baz param can be omitted during the invocation of foo
Solution
Then you can use the following syntax
func foo(bar: String, #noescape baz: ((String) -> ()) = { _ in } ) {
}
As you can see the main difference from your code is that:
here baz is not an optional type (but it's an "optional parameter")
and its default value is an empty closure not a nil value.
Examples
As you requested you can now pass a closure to baz without the need of using self
class Boo {
let world = "world"
func boo() {
foo("hello") { (something) -> () in
print(world)
}
}
}
And you can also omit the baz param
class Boo {
let world = "world"
func boo() {
foo("hello")
}
}
Update: using a closure with return type different from Void
In a comment below users TadeasKriz asked about how to use this approach with a closure having the return value different the Void.
Here it is the solution
func foo(bar: String, #noescape baz: ((String) -> (Int)) = { _ in return 0 } ) {
}
Here the baz param does required a closure with 1 param of type String and a return value of type Int.
As you can see I added a default value to the param, a closure that does return 0. Please note that the default closure will never be used so you can replace 0 with any Int value you want.
Now you can decide whether to use pass your closure to the baz param
class Boo {
let world = "world"
func boo() {
foo("hello") { (something) -> Int in
print(world)
return 100
}
}
}
Or, again, you can totally omit the baz param.
class Boo {
let world = "world"
func boo() {
foo("hello")
}
}
Related
I have this code, but it shows error:
extension Collection {
func removingOptionals() -> [Element] {
var result = [Element](); // Error: cannot call value of non-function type '[Self.Element.Type]'
self.forEach({ (element) in if let el = element { result.append(el); } });
return result;
}
}
If I removed the (), the error becomes: Expected member name or constructor call after type name.
This code is supposed to transform [String?] into [String] by discarding all the null values. Or any other optional data types.
How can I do this?
You can use flatMap {} for this, instead of creation own function. Here is example of usage:
let strings: [String?] = ["One", nil, "Two"]
print(strings.flatMap { $0 })
And result will be ["One", "Two"]
You can continue to use the flatMap behavior of the Optional as the other answer shows, but it's going to be deprecated on the next Swift iteration.
If you want to add the extension to the collection type, you need to be a create a type to box the Optional (You can't extend Collection if the type is generic, like Optional).
protocol OptionalType {
associatedtype Wrapped
func map<U>(_ f: (Wrapped) throws -> U) rethrows -> U?
}
extension Optional: OptionalType {}
extension Collection where Iterator.Element: OptionalType {
func removeNils() -> [Iterator.Element.Wrapped] {
var result: [Iterator.Element.Wrapped] = []
result.reserveCapacity(Int(self.count))
for element in self {
if let element = element.map({ $0 }) {
result.append(element)
}
}
return result
}
}
Consider the following code:
protocol Foo {
func f() -> Void
}
class Bar1: Foo {
func f() {
print("Bar1 f")
}
}
class Bar2: Foo {
func f() {
print("Bar2 f")
}
}
func function<T:Foo>(arg:T = Bar2()) {
arg.f()
}
It gives an error Value of type Bar2 cannot be converted to type T, which seems to be pure nonsense, because T is guaranteed to be compatible with Foo and this is the context within which the assignment should operate.
To prove it:
let global: Foo = Bar2()
global.f()
This works just fine.
I am wondering why such a discrepancy exists and if there is any workaround for it?
Cast the Bar2() as Generic type T
func function<T:Foo>(arg:T = Bar2() as! T) {
arg.f()
}
I'd like to understand why the expanded method works while the nil-coalescing operator version tells that there is some ambiguity trying to compile it.
typealias SendBlock = ([NSArray]) -> Void
var callbacks = [SendBlock]()
func functionWithArgs(callback: SendBlock?) {
callbacks.append(callback ?? { _ in })
}
func functionWithArgsExpanded(callback: SendBlock?) {
if let cb = callback {
callbacks.append(cb)
} else {
callbacks.append({ _ in })
}
}
It’s because of the #autoclosure used on the rhs argument of ??. Something about that means it doesn’t like actually receiving a closure as the type of the thing being coalesced.
Just to demonstrate the location of the issue (don’t do this as a workaround), if you redefine a version of ?? without it, it’s fine:
typealias SendBlock = () -> Void
var callbacks = [SendBlock]()
infix operator !! { }
func !!<T>(optional: T?, defaultValue: T)->T {
return optional != nil ? optional! : defaultValue
}
func functionWithArgs(callback: SendBlock?) {
callbacks.append( callback !! { _ in })
}
functionWithArgs { _ in println("blah") }
// just to prove it works… prints “blah”
for x in callbacks { x() }
But if you amend the operator to use an #autoclosure:
func !!<T>(optional: T?, #autoclosure defaultValue: ()->T)->T {
return optional != nil ? optional! : defaultValue()
}
You get your error:
error: type of expression is ambiguous without more context
callbacks.append( callback !! { _ in })
^
I’d say this is a bug and you should file a report. In the mean-time your workaround is probably the best you’ll do.
I think it's just a bug in the compiler. It works just fine if you substitute String every place you have SendBlock.
Evidently, the compiler chokes on the use of the nil-coalescing operator with an Optional wrapping a function type. You get a more revealing error if you write it like this:
func functionWithArgs(callback: SendBlock?) {
let sb : SendBlock = { _ in }
callbacks.append(callback ?? sb)
}
The error reads: "Binary operator ?? cannot be applied to operands of type SendBlock? and SendBlock." To which one wants to reply: Of course it can! Those are exactly the sorts of operand to which it can be applied: an Optional and its unwrapped form.
This question already has answers here:
Closure with generic parameters
(2 answers)
Closed 7 months ago.
func myfunc<T>(i:T) -> T {
return i
}
is it possible to make this generic function a closure?
let myfunc = { <T>(i:T) -> T in
return i
}
this doesn't work...
No, because variables and expressions can't be generic. There are only generic functions and generic types.
To clarify: In some languages you can have types with a universal quantifier, like forall a. a -> a. But in Swift, types cannot have a universal quantifier. So expressions and values cannot be themselves generic. Function declarations and type declarations can be generic, but when you use such a generic function or an instance of such a generic type, some type (which could be a real type or a type variable) is chosen as the type argument, and thereafter the value you get is no longer itself generic.
Probably you need something like this.
Type declaration:
typealias ResultClosure<T> = (ResultCode, String?, T?) -> Void
Function declaration:
func loginUser(userName: String, password: String, resultHandler: ResultClosure<TokenModel>?)
Usage:
NetConnector.shared.loginUser(userName: userName ?? "", password: password ?? "") { (code, message, data) in
self.display?.unlockScreen()
if code == .success {
if let activeToken = data {
AppData.shared.userToken = activeToken
}
self.display?.showHome()
} else {
self.display?.showError(errorMessage: message)
}
}
As mentioned, variables in Swift cannot be generic, so creating a closure, whose generic types are specified by the caller is not possible. However, there are workarounds:
With SE-253, it is possible to make arbitrary (nominal) types callable. So instead of declaring a generic closure, we can declare a (non-generic) struct that has a generic callAsFunction method:
struct MyFunc {
func callAsFunction<T>(_ i: T) -> T {
return i
}
}
Now, we can declare a non-generic variable that we can call with a generic value:
let myFunc = MyFunc()
let x = myFunc(42) // -> Int
let y = myFunc("foo") // -> String
Note that this workaround doesn't apply to all situations, but it can be helpful in some.
I have found some alternative way , you can use Anyobject in your closure and pass any values to your method .
typealias genericCompletion<T:AnyObject> = ((Bool,T,String) -> Void)
struct Student {
var name:String = "Kishore"
var age : String = "125"
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.createAGenericReturn { (success, object, message) in
}
self.createStructGeneric { (success, student, message) in
}
}
func createAGenericReturn(callback:#escaping(genericCompletion<AnyObject>)){
callback(true,434.433 as AnyObject,"kishoreTest")
}
func createStructGeneric(callback:#escaping(genericCompletion<AnyObject>)){
callback(true,Student.init() as AnyObject,"kishoreTest")
}
}
Here you can see I mentioned Generic as Anyobject typealias genericCompletion = ((Bool,T,String) -> Void) , So you can pass any values to it .
I noticed when writing an assert in Swift that the first value is typed as
#autoclosure() -> Bool
with an overloaded method to return a generic T value, to test existence via the LogicValue protocol.
However sticking strictly to the question at hand. It appears to want an #autoclosure that returns a Bool.
Writing an actual closure that takes no parameters and returns a Bool does not work, it wants me to call the closure to make it compile, like so:
assert({() -> Bool in return false}(), "No user has been set", file: __FILE__, line: __LINE__)
However simply passing a Bool works:
assert(false, "No user has been set", file: __FILE__, line: __LINE__)
So what is going on? What is #autoclosure?
Edit: #auto_closure was renamed #autoclosure
Consider a function that takes one argument, a simple closure that takes no argument:
func f(pred: () -> Bool) {
if pred() {
print("It's true")
}
}
To call this function, we have to pass in a closure
f(pred: {2 > 1})
// "It's true"
If we omit the braces, we are passing in an expression and that's an error:
f(pred: 2 > 1)
// error: '>' produces 'Bool', not the expected contextual result type '() -> Bool'
#autoclosure creates an automatic closure around the expression. So when the caller writes an expression like 2 > 1, it's automatically wrapped into a closure to become {2 > 1} before it is passed to f. So if we apply this to the function f:
func f(pred: #autoclosure () -> Bool) {
if pred() {
print("It's true")
}
}
f(pred: 2 > 1)
// It's true
So it works with just an expression without the need to wrap it in a closure.
Here's a practical example — my print override (this is Swift 3):
func print(_ item: #autoclosure () -> Any, separator: String = " ", terminator: String = "\n") {
#if DEBUG
Swift.print(item(), separator:separator, terminator: terminator)
#endif
}
When you say print(myExpensiveFunction()), my print override overshadows Swift's print and is called. myExpensiveFunction() is thus wrapped in a closure and not evaluated. If we're in Release mode, it will never be evaluated, because item() won't be called. Thus we have a version of print that doesn't evaluate its arguments in Release mode.
Description of auto_closure from the docs:
You can apply the auto_closure attribute to a function type that has a
parameter type of () and that returns the type of an expression (see
Type Attributes). An autoclosure function captures an implicit closure
over the specified expression, instead of the expression itself. The
following example uses the auto_closure attribute in defining a very
simple assert function:
And here's the example apple uses along with it.
func simpleAssert(condition: #auto_closure () -> Bool, message: String) {
if !condition() {
println(message)
}
}
let testNumber = 5
simpleAssert(testNumber % 2 == 0, "testNumber isn't an even number.")
Basically what it means is you pass a boolean expression as that first argument instead of a closure and it automatically creates a closure out of it for you. That's why you can pass false into the method because it is a boolean expression, but can't pass a closure.
This shows a useful case of #autoclosure https://airspeedvelocity.net/2014/06/28/extending-the-swift-language-is-cool-but-be-careful/
Now, the conditional expression passed as the first parameter to until will be automatically wrapped up into a closure expression and can be called each time around the loop
func until<L: LogicValue>(pred: #auto_closure ()->L, block: ()->()) {
while !pred() {
block()
}
}
// doSomething until condition becomes true
until(condition) {
doSomething()
}
It's just a way to get rid of the curly braces in a closure call, simple example:
let nonAutoClosure = { (arg1: () -> Bool) -> Void in }
let non = nonAutoClosure( { 2 > 1} )
let autoClosure = { (arg1: #autoclosure () -> Bool) -> Void in }
var auto = autoClosure( 2 > 1 ) // notice curly braces omitted
#autoclosure
#autoclosure converts(wraps) expression inside function parameter in a closure[About]
Pros:
easy to read assert(2 == 5, "failed")
curly braces are not used
Cons
hard to read. When you pass a function inside #autoclosure it is not clear that this function will be deferred(because it is closure inside). fooWithAutoClosure(a: foo0()) - foo0() will be called not immediately as we expect reading this line
Overusing autoclosures can make your code hard to understand. The context and function name should make it clear that evaluation is being deferred.
Official doc
#autoclosure doesn't take any parameters
func foo(p: #autoclosure () -> Void)
#autoclosure accept any function with only appropriate returned type
More examples
//functions block
func foo0() -> String {
return "foo0"
}
func foo1(i1: Int) -> String {
return "foo1 " + String(i1)
}
func foo2(i1: Int, i2: Int) -> String {
return "foo2 " + String(i1 + i2)
}
//closures block
func fooWithClosure0(p: () -> String) -> String {
return "fooWithClosure0 " + p()
}
func fooWithClosure1(p: (Int) -> String) -> String {
return "fooWithClosure1 " + p(1)
}
func fooWithClosure2(p: (Int, Int) -> String) -> String {
return "fooWithClosure2 " + p(1, 2)
}
//#autoclosure
func fooWithAutoClosure(a: #autoclosure () -> String) -> String {
return "fooWithAutoClosure " + a()
}
//test closures
func testClosures() {
XCTAssertEqual("fooWithClosure0 foo0", fooWithClosure0(p: foo0))
XCTAssertEqual("fooWithClosure1 foo1 1", fooWithClosure1(p: foo1))
XCTAssertEqual("fooWithClosure2 foo2 3", fooWithClosure2(p: foo2))
XCTAssertEqual("fooWithClosure2 foo2 3", fooWithClosure2(p: { (i1, i2) -> String in
return "fooWithClosure2 " + "foo2 " + String(i1 + i2)
}))
}
//test #autoclosure
func testAutoClosures() {
XCTAssertEqual("fooWithAutoClosure HelloWorld", fooWithAutoClosure(a: "HelloWorld")) //"HelloWorld" is String as returned value of #autoclosure
XCTAssertEqual("fooWithAutoClosure foo0", fooWithAutoClosure(a: foo0()))
XCTAssertEqual("fooWithAutoClosure foo1 1", fooWithAutoClosure(a: foo1(i1: 1)))
XCTAssertEqual("fooWithAutoClosure foo2 3", fooWithAutoClosure(a: foo2(i1: 1, i2: 2)))
}