Skip to Content
Course content

116: Defer Statements for Cleanup

Click on the "Edit" button in the top corner of the screen to edit your slide content.

When I first started working with defer in Swift, I fell into a trap that I see a lot of developers fall into today. I assumed that defer was essentially a "catch" or "error" block—something that only triggered if the function failed or threw an exception. I treated it like a safety net for when things went sideways.

"Defer only runs when an error occurs"

That assumption is completely wrong. If you write your cleanup logic assuming defer is only for failures, you're going to be very surprised when your resources start closing in the middle of a perfectly successful execution. Let me show you what I mean.

func processUserPreferences() {
    print("Opening preferences file...")
    
    defer {
        print("Closing preferences file.")
    }
    
    print("Reading settings...")
    if true { 
        print("Found a conflict, returning early!")
        return 
    }
    
    print("This line will never be reached.")
}

processUserPreferences()
// Output:
// Opening preferences file...
// Reading settings...
// Found a conflict, returning early!
// Closing preferences file.

Notice that nothing "went wrong" here. We didn't throw an error; we simply decided to return early. Yet, the defer block executed anyway. defer doesn't care why you are leaving the scope—whether it's a normal return, a throw, or simply reaching the closing brace of the function—it just ensures that the code inside it runs before the scope is officially destroyed.

Guaranteeing cleanup regardless of the exit path

The real power of defer is that it allows you to place your cleanup logic immediately next to your initialization logic. In the old days of C or Java, you'd open a file at the top of a function and then have to remember to call close() at every single return point in that function. If you had five different if/else blocks returning early, you had to write close() five times. It was a nightmare for maintenance.

With defer, you "schedule" the cleanup the moment you acquire the resource. I personally find this much safer because I don't have to scroll through 50 lines of logic to make sure I didn't forget to release a lock or close a handle.

func uploadLogFile(url: URL) throws {
    let fileHandle = try FileHandle(forReadingFrom: url)
    
    // I schedule the closure right here, so I can forget about it
    defer {
        fileHandle.closeFile()
        print("File handle released.")
    }
    
    let data = fileHandle.readDataToEndOfFile()
    if data.isEmpty {
        throw LogError.emptyFile // defer still runs!
    }
    
    try networkClient.upload(data) // defer still runs!
}

One detail that often trips people up: if you have multiple defer statements in one block, they execute in reverse order (Last-In, First-Out). Think of it like a stack of plates. The last cleanup task you schedule is the first one that gets executed. This is actually incredibly useful when your resources depend on each other—for example, if you open a database connection and then start a transaction, you want to commit/close the transaction before you close the connection.




📋 Practical Task

Exercise: Managing a Mock Database Connection

You are building a data migration tool. You need to create a function called migrateUserData() that simulates interacting with a database. To make this realistic, you should simulate the following sequence:

  • Print "Connecting to Database..."
  • Use a defer block to print "Database connection closed."
  • Print "Starting Transaction..."
  • Use a second defer block to print "Transaction committed/rolled back."
  • Simulate a conditional failure: Create a boolean variable shouldFail. If it is true, print "Migration failed!" and return from the function early.
  • If it doesn't fail, print "Migration completed successfully!"

Goal: Verify that both cleanup messages print in the correct reverse order (Transaction first, then Connection) regardless of whether shouldFail is true or false.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.