C.W.K.
Stream
Lesson 01 of 05 · published

File Calls Block Forever

~12 min · main-thread, blocking-io, responsiveness

Level 0Lost in Finder
0 XP0/36 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"Every beachball you've ever cursed at a file manager is a file call that ran where the UI lives."

The Warning in Apple's Own Docs

This isn't Waygate being cautious for fun. Apple's file-system guidance says it plainly: file calls can block for an indeterminate amount of time on file providers, USB media, and SMB. "Indeterminate" is the scary word — not "a little slow," but "possibly seconds, possibly until a timeout, possibly until a spun-down disk wakes." If that call runs on the main thread, the entire UI is frozen for exactly that long, and the user gets the spinning beachball that every network file manager is infamous for.

The Rule: Nothing Slow on the Main Thread

Waygate's rule is absolute: enumeration, metadata reads, preview generation, and every mutation run off the main thread. Not just the obviously-slow network ones — all of them. The reason is that you often can't tell in advance which call will stall. A 'local' path might be a mounted network folder; a 'fast' metadata read might trigger a cloud provider to wake up. Treating all file I/O as potentially-blocking is the only rule that doesn't have a hole in it.

Off-Main Means Cancellable and Timed

Moving work off the main thread isn't just about not freezing — it's what makes work cancellable. A slow enumeration on a dying SMB share can be canceled and the pane marked offline, instead of hanging forever. Every off-main file task carries cancellation and timeout states, so 'this is taking too long' becomes a handled outcome the UI can show, not a dead app the user has to force-quit.

Enumeration, metadata, preview, and mutation all run off the main thread, with cancellation and timeout states. File calls can block for an indeterminate time on providers, USB, and SMB, so 'probably fast' is never a reason to run I/O on the main thread. The main thread's only job is to stay responsive; the filesystem's unpredictability lives on other threads.
'It's just a quick stat call' is the classic freeze. The bug that beachballs a file manager is almost never the big obvious copy — it's a 'harmless' metadata or icon read on the main thread that happened to touch a stalled volume. Because it looked fast, nobody moved it off-main. There is no such thing as a reliably-fast file call; the volume decides, not your code.

Code

Wrong: enumeration on the main thread freezes the app·swift
// WRONG -- if `folder` is a slow SMB share, the WHOLE UI hangs here:
@IBAction func openFolder(_ sender: Any) {
    let contents = try! FileManager.default.contentsOfDirectory(   // BLOCKS main thread
        at: folder, includingPropertiesForKeys: [.fileSizeKey])
    tableView.reloadData(with: contents)
}

// RIGHT -- off-main, cancellable, with a timeout state the UI can show:
func openFolder(_ folder: LocationReference) {
    enumerationTask = Task {
        do {
            let rows = try await enumerator.list(folder)   // runs off-main
            await MainActor.run { present(rows) }
        } catch is CancellationError {
            await MainActor.run { markPaneOffline(folder) } // handled, not hung
        }
    }
}

External links

Exercise

Open a file manager (any one) and navigate into a network share, then pull the network or eject the drive mid-navigation. Watch what happens to the whole app. Now explain, in terms of threads, why the app froze — and what off-main enumeration with a timeout would have shown the user instead.
Hint
The freeze happens because the enumeration call is running on the main thread, which is also the thread that draws the UI and handles clicks — so while the call waits on the dead share, nothing can repaint or respond. Off-main enumeration would let the main thread keep running; a timeout would turn the stall into a visible 'this location is offline' state instead of a beachball.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.