nateslager nateslager - 19 days ago 6
Swift Question

Closure not compiling when setting GKLocalPlayer's authenticateHandler property - Swift 3.0

This and this don't compile.

The code in my SpriteKitSceneViewController,

var localPlayer = GKLocalPlayer.localPlayer()
localPlayer.authenticateHandler = {((viewController : UIViewController?, error : NSError?) -> Void)? in
//handle authentication
}


produces these errors:

Consecutive statements on a line must be separated by ';'

Expected expression

The authenticated property is defined as:

var authenticateHandler: ((UIViewController?, Error?) -> Void)? { get set }


I've read the documentation on closures, but I didn't find anything on optional closures. I thought about using a function instead but I couldn't get that to work either. How can I make this compile?

Answer

You need to write closure-signature at the top of the closure-expression. (It's conditionally optional.)

In your code ((viewController : UIViewController?, error : NSError?) -> Void)? is not a valid closure-signature, you need to remove outermost (...)?.

And when you write parameter types explicitly, they need to match exactly as the parameter types of the closure type. So, your second parameter's type needs to be Error?, not NSError?.

With two things above fixed, you can write something like this:

localPlayer.authenticateHandler = {(viewController : UIViewController?, error : Error?) -> Void in
    //handle authentication
}

But omitting all unneeded parts, you can write it more easily:

localPlayer.authenticateHandler = {viewController, error in
    //handle authentication
}

In most cases, you can omit->Void, and in almost all cases, Swift can infer the parameter types. I prefer omitting type annotations when Swift would never fail to infer them.