Hans Brende Hans Brende - 18 days ago 8
Swift Question

Weird escaping function behavior after updating to Swift 3

I'm having difficulties with the following lines of code after updating to Swift 3:

private var functionHandlers = [(() -> Int) -> ()]()

private var myFunction: (() -> Int)?

func doRegister() {
functionHandlers.append { (f: (() -> Int)) in
myFunction = f
}
}


That gave me the compiler error:
Assigning non-escaping parameter 'f' to an escaping closure


So then, I tried this:

func doRegister() {
functionHandlers.append { (f: @escaping (() -> Int)) in
myFunction = f
}
}


and this:

func doRegister() {
functionHandlers.append { (f: (@escaping () -> Int)) in
myFunction = f
}
}


which, in both cases, fixed my first error, but then gave me a new compiler error:
Cannot convert value of type '(@escaping (() -> Int)) -> ()' to expected argument type '(() -> Int) -> ()'


So then I tried changing the type of
functionHandlers
as follows:

private var functionHandlers = [(@escaping (() -> Int)) -> ()]()


but that just resulted in a syntax error.

Can anyone explain to me why this is happening and what I can do to fix this?

Answer

Looks like a bug to me. For some reason, the compiler doesn't like the syntax:

private var functionHandlers = [(@escaping () -> Int) -> ()]()

but it does like:

private var functionHandlers : [(@escaping () -> Int) -> ()] = []

It's the same symptom, but I'm unsure it's the same cause as the compiler rejecting the [TypeA.TypeB]() syntax with nested types. Although like that problem, another way of solving it is by using a typealias:

typealias F = (@escaping () -> Int) -> ()

private var functionHandlers = [F]()

You can then implement doRegister() as you correctly tried to implement it as:

func doRegister() {
    functionHandlers.append { (f: @escaping () -> Int) in
        myFunction = f
    }
}

Although you should certainly file a bug report over [(@escaping () -> Int) -> ()]() not compiling.

Comments