Communitygithub.com

persistance-avec-acteurs-swift

Persistance de données thread-safe en Swift utilisant des acteurs — cache en mémoire avec stockage sur fichier, éliminant les accès concurrents par conception. À utiliser pour persister des données en Swift lorsque des problèmes d'accès concurrent ou de thread-safety doivent être résolus.

Qu'est-ce que persistance-avec-acteurs-swift ?

Cette compétence fournit des patrons de conception pour construire des couches de persistance de données thread-safe en Swift en utilisant le modèle d'acteurs. Elle combine un cache en mémoire avec un stockage sur fichier pour garantir à la fois des lectures rapides et des écritures durables, tout en éliminant les accès concurrents (data races) au moment de la compilation. Destinée aux développeurs Swift, elle supporte les applications iOS/macOS et les architectures offline-first. La compétence détaille un `LocalRepository` générique basé sur un acteur Swift, avec des méthodes pour sauvegarder, supprimer et rechercher des données, ainsi que des conseils sur les bonnes pratiques et les anti-patrons à éviter.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/swift-actor-persistence

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Acteurs Swift pour une Persistance Thread-Safe

Patrons pour construire des couches de persistance de données thread-safe en utilisant les acteurs Swift. Combine le cache en mémoire avec le stockage sur fichier, en tirant parti du modèle d'acteur pour éliminer les accès concurrents au moment de la compilation.

Quand Activer

  • Construire une couche de persistance de données en Swift 5.5+
  • Besoin d'accès thread-safe à un état mutable partagé
  • Vouloir éliminer la synchronisation manuelle (verrous, DispatchQueues)
  • Construire des applications offline-first avec un stockage local

Patron Principal

Référentiel Basé sur un Acteur

Le modèle d'acteur garantit un accès sérialisé — pas d'accès concurrents, assuré par le compilateur.

public actor LocalRepository<T: Codable & Identifiable> where T.ID == String {
    private var cache: [String: T] = [:]
    private let fileURL: URL

    public init(directory: URL = .documentsDirectory, filename: String = "data.json") {
        self.fileURL = directory.appendingPathComponent(filename)
        // Chargement synchrone pendant l'init (isolation de l'acteur pas encore active)
        self.cache = Self.loadSynchronously(from: fileURL)
    }

    // MARK: - API Publique

    public func save(_ item: T) throws {
        cache[item.id] = item
        try persistToFile()
    }

    public func delete(_ id: String) throws {
        cache[id] = nil
        try persistToFile()
    }

    public func find(by id: String) -> T? {
        cache[id]
    }

    public func loadAll() -> [T] {
        Array(cache.values)
    }

    // MARK: - Méthodes Privées

    private func persistToFile() throws {
        let data = try JSONEncoder().encode(Array(cache.values))
        try data.write(to: fileURL, options: .atomic)
    }

    private static func loadSynchronously(from url: URL) -> [String: T] {
        guard let data = try? Data(contentsOf: url),
              let items = try? JSONDecoder().decode([T].self, from: data) else {
            return [:]
        }
        return Dictionary(uniqueKeysWithValues: items.map { ($0.id, $0) })
    }
}

Utilisation

Tous les appels sont automatiquement asynchrones en raison de l'isolation de l'acteur :

let repository = LocalRepository<Question>()

// Lecture — recherche rapide O(1) dans le cache en mémoire
let question = await repository.find(by: "q-001")
let allQuestions = await repository.loadAll()

// Écriture — met à jour le cache et persiste dans le fichier de manière atomique
try await repository.save(newQuestion)
try await repository.delete("q-001")

Combinaison avec un ViewModel @Observable

@Observable
final class QuestionListViewModel {
    private(set) var questions: [Question] = []
    private let repository: LocalRepository<Question>

    init(repository: LocalRepository<Question> = LocalRepository()) {
        self.repository = repository
    }

    func load() async {
        questions = await repository.loadAll()
    }

    func add(_ question: Question) async throws {
        try await repository.save(question)
        questions = await repository.loadAll()
    }
}

Décisions de Conception Clés

DécisionJustification
Acteur (plutôt que classe + verrou)Sécurité thread-safe assurée par le compilateur, pas de synchronisation manuelle
Cache en mémoire + persistance fichierLectures rapides depuis le cache, écritures durables sur le disque
Chargement synchrone dans l'initÉvite la complexité de l'initialisation asynchrone
Dictionnaire indexé par IDRecherches O(1) par identifiant
Générique sur Codable & IdentifiableRéutilisable pour tout type de modèle
Écritures atomiques (.atomic)Empêche les écritures partielles en cas de crash

Bonnes Pratiques

  • Utiliser des types Sendable pour toutes les données traversant les frontières de l'acteur
  • Garder l'API publique de l'acteur minimale — n'exposer que les opérations métier, pas les détails de persistance
  • Utiliser des écritures .atomic pour éviter la corruption des données si l'application plante en pleine écriture
  • Charger de manière synchrone dans init — les initialiseurs asynchrones ajoutent de la complexité avec peu d'avantages pour les fichiers locaux
  • Combiner avec des ViewModels @Observable pour des mises à jour réactives de l'interface utilisateur

Anti-Patrons à Éviter

  • Utiliser DispatchQueue ou NSLock plutôt que des acteurs pour du nouveau code de concurrence Swift
  • Exposer le dictionnaire de cache interne aux appelants externes
  • Rendre l'URL du fichier configurable sans validation
  • Oublier que tous les appels aux méthodes de l'acteur nécessitent await — les appelants doivent gérer le contexte asynchrone
  • Utiliser nonisolated pour contourner l'isolation de l'acteur (cela va à l'encontre du but recherché)

Quand Utiliser

  • Stockage de données local dans les applications iOS/macOS (données utilisateur, paramètres, contenu mis en cache)
  • Architectures offline-first qui se synchronisent plus tard avec un serveur
  • Tout état mutable partagé auquel plusieurs parties de l'application accèdent simultanément
  • Remplacer la sécurité thread-safe basée sur DispatchQueue par la concurrence moderne de Swift

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

Skills associés