Skip to content

What is Closure?

A closure is a self-contained block of functionality that can be passed around and used in your code

Tip

Closures are widely used in Swift programming for things like callbacks, completion handlers, and functional programming techniques.

  1. Closures that can be called after the function they were passed to has returned.
  2. Declared with @escaping.
        var completionClosure: (() -> Void)?
    
        func doSomethingEscaping(closure: @escaping () -> Void) {
            // This closure is escaping, so we can store it for later execution.
            completionClosure = closure
        }
    
        func exampleUsage() {
            doSomethingEscaping {
                print("This is an escaping closure.")
            }
    
            // At a later point in the code, we can execute the escaping closure.
            completionClosure?()
        }
    
    Example
        exampleUsage()
    
    Output
        This is an escaping closure.
    
  1. Closures that do not outlive the function they are passed to.
  2. They are executed within the function's scope.
        //Example of a non-escaping closure:
        func doSomethingNonEscaping(closure: () -> Void) {
            // This closure is non-escaping, so it must be called within this function.
            closure()
        }
    
        func exampleUsage() {
            doSomethingNonEscaping {
                print("This is a non-escaping closure.")
            }
        }
    
    Example
        exampleUsage();
    
    Output
        This is a non-escaping closure.
    

Autoclosures

  1. It automatically created to wrap an expression that’s being passed as an argument to a function.
  2. It doesn’t take any arguments.

    func printIfTrue(_ predicate: @autoclosure () -> Bool) {
        if predicate() {
            print("It's true!")
        } else {
            print("It's false!")
        }
    }
Example
    printIfTrue(2 > 1)
    printIfTrue(2 < 1)
Output
    It's true!
    It's false!

   enum LogLevel: Int {
        case debug = 1
        case info
        case warning
        case error
    }

    var currentLogLevel: LogLevel = .debug

    func log(_ level: LogLevel, message: @autoclosure () -> String) {
        if level.rawValue >= currentLogLevel.rawValue {
            print(message())
        }
    }
Example
    // Logging with different levels
    log(.debug, message: "This is a debug message")
    log(.info, message: "This is an info message")
    log(.warning, message: "This is a warning message")
    log(.error, message: "This is an error message")
    // Only the message for the current log level or higher will be printed
    currentLogLevel = .warning
    log(.debug, message: detailedDebugMessage)
    log(.info, message: "This info message won't be printed")
    log(.warning, message: "This is a warning message")
    log(.error, message: "This is an error message")
Output
    This is a debug message
    This is an info message
    This is a warning message
    This is an error message
    This is a warning message
    This is an error message


Let's grow together 🌱

Cheers 🍻