shredbx logo
shredbx shredbx shredbx shredbx Personal
  • Home
  • Lab
  • Portfolio
  • Experience
  • Services
  • Profile
  • Contact
AClaude
  • Home
  • Lab
  • Portfolio
  • Experience
  • Services
  • Profile
  • Contact
Andrei Solovev
Knowledge
Search knowledge... ⌘K
Knowledge · Guidelines · swift

Swift Appkit Crash Recovery Persistence

Crash-safe persistence for AppKit apps using debounced atomic writes to applicationSupportDirectory, applicationWillTerminate flush hook, and recovery-stamp behavior on load. Guarantees the user never loses more than a few hundred milliseconds of work even if the app is force-quit mid-session.

Andrei Solovev

Metadata

swift swift mandatory

Procedures

Showing 3 of 6

  1. 1 Write to FileManager.applicationSupportDirectory, not Documents
    ```swift
    private static var persistenceFileURL: URL {
        let base = (try? FileManager.default.url(
            for: .applicationSupportDirectory,
            in: .userDomainMask,
            appropriateFor: nil,
            create: true
        )) ?? FileManager.default.homeDirectoryForCurrentUser
            .appendingPathComponent("Library/Application Support")
        let dir = base.appendingPathComponent("Whisperbar", isDirectory: true)
        if !FileManager.default.fileExists(atPath: dir.path) {
            try? FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
        }
        return dir.appendingPathComponent("history.json")
    }
    ```
    Application Support is sandbox-scoped, not Spotlight-indexed,
    and not user-visible in Finder by default — the right home for
    internal state.
  2. 2 Use debounced writes (300ms) via DispatchWorkItem
    ```swift
    private var saveWorkItem: DispatchWorkItem?
    private func scheduleSave() {
        saveWorkItem?.cancel()
        let snapshot = self.history  // capture by value
        let item = DispatchWorkItem {
            let url = Self.persistenceFileURL
            do {
                let encoder = JSONEncoder()
                encoder.dateEncodingStrategy = .iso8601
                encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
                let data = try encoder.encode(snapshot)
                try data.write(to: url, options: .atomic)
            } catch { /* log metadata only */ }
        }
        saveWorkItem = item
        DispatchQueue.global(qos: .utility).asyncAfter(deadline: .now() + 0.3, execute: item)
    }
    ```
    `.atomic` write is critical — it writes to a temp file and
    renames, so the file is never partially written on crash.
  3. 3 Expose flushNow() that cancels the pending work item and runs it synchronously
    ```swift
    func flushNow() {
        saveWorkItem?.cancel()
        let snapshot = self.history
        // Run synchronously on calling queue:
        // (implementation of the write block — same as in scheduleSave)
        performSaveSync(snapshot)
    }
    ```
shredbx logo shredbx shredbx shredbx shredbx Andrei Solovev

Solution Architect & Lead Software Engineer

ExperiencePortfolioResearch & ExperimentsEducationCertificationSkills
GitHub ↗LinkedIn ↗Email ↗
AVAILABLE FOR NEW PROJECTS
// MY LATEST BEATS
Hobby & Interests

Lab

  • The Lab
  • Framework
  • Components
  • Packages
  • Games
  • Process (SDLC)
  • Knowledge
  • Blog

Andrei

  • Portfolio
  • Experience
  • Services
  • Profile
  • Contact
  • Lifestyle

Team

  • Team
  • Andrei
  • Claude

Legal

  • Privacy
  • Terms
  • Cookies
© 2026 shredbx.com. All rights reserved. — Andrei Solovev |