Swift
programming
optional binding
nil checking
error handling

optional closure and check if it is nil

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Swift, a closure can be optional just like any other value. That means the closure may or may not exist, and the caller has to deal with that possibility safely. The most idiomatic approach is usually not to write a long manual nil check, but to use optional chaining or optional binding depending on whether you only want to call the closure or also need to inspect it first.

Declare an Optional Closure

An optional closure type looks like this:

swift
var completion: (() -> Void)?

That means completion is either:

  • a closure that takes no arguments and returns Void
  • or nil

The same idea works for closures with parameters:

swift
var onResult: ((String) -> Void)?

Now the closure may accept a String, but it is still optional.

Call It with Optional Chaining

If you only want to call the closure when it exists, optional chaining is the cleanest pattern.

swift
var completion: (() -> Void)?

completion?()

If completion is nil, nothing happens. If it contains a closure, Swift calls it.

This is usually better than writing a verbose nil check for simple callback execution.

Use if let When You Need the Closure Value

If you need to hold onto the closure briefly, log something, or call it several times in the same block, bind it first.

swift
1var onResult: ((String) -> Void)? = { value in
2    print("Received: \(value)")
3}
4
5if let callback = onResult {
6    callback("Hello")
7}

This is also useful if the code would be harder to read with repeated optional chaining.

Checking Whether It Is Nil

If you specifically need to know whether the optional closure is present, compare it to nil.

swift
if completion == nil {
    print("No completion handler provided")
}

That is fine when the presence or absence itself affects control flow. But if the only goal is to call it when available, completion?() is still the more idiomatic form.

Optional Closures as Function Parameters

Optional closures are common in APIs where a completion handler is allowed but not required.

swift
1func loadData(completion: (() -> Void)? = nil) {
2    print("Loading...")
3    completion?()
4}
5
6loadData()
7loadData {
8    print("Finished")
9}

This combines an optional closure with a default value of nil, making the callback truly optional for the caller.

Escaping Closures Still Work the Same Way

If the closure is stored or used later, it may still need @escaping even when it is optional.

swift
1class Loader {
2    var completion: (() -> Void)?
3
4    func setCompletion(_ callback: @escaping () -> Void) {
5        completion = callback
6    }
7}

Optionality and escaping solve different problems:

  • optionality means the closure may be absent
  • escaping means the closure may outlive the current function call

It helps to keep those concerns separate.

Avoid Force-Unwrapping Optional Closures

This is legal but risky:

swift
completion!()

If completion is nil, the program crashes. Force-unwrapping is only reasonable when some earlier guarantee makes nil impossible and that guarantee is truly solid. In ordinary Swift code, optional chaining is the safer default.

When a Non-Optional Closure Is Better

Sometimes the real answer is not an optional closure at all. If the closure is always required for correct behavior, make it non-optional and force callers to supply it.

swift
func process(value: Int, handler: (Int) -> Void) {
    handler(value)
}

This simplifies the API and removes one whole category of nil-handling logic.

Common Pitfalls

  • Writing manual nil checks when closure?() would be clearer.
  • Force-unwrapping an optional closure and risking a crash.
  • Treating @escaping and optionality as if they solved the same problem.
  • Making a closure optional when the API really requires it.
  • Forgetting that optional closures can still be stored, passed around, and called later like any other optional value.

Summary

  • An optional closure in Swift is just a closure value that may also be nil.
  • Use optional chaining such as completion?() when you only need to call it if present.
  • Use if let when you need to bind the closure and work with it explicitly.
  • Avoid force-unwrapping unless absence is truly impossible.
  • If the callback is required, make it non-optional instead of modeling it as maybe missing.

Course illustration
Course illustration

All Rights Reserved.