swift-actor-persistence
Faz seu agente gerenciar dados de forma segura em Swift. Ele usa 'actors' para evitar problemas de concorrência, garantindo que os dados não sejam corrompidos.
O que ela faz
Este código ajuda a guardar informações importantes no seu aplicativo de forma segura, mesmo que várias partes do app tentem acessar ao mesmo tempo. Ele salva os dados na memória para acesso rápido e também em um arquivo para não se perder.
Quando usar
- ✓Guardar dados do usuário em um app.
- ✓Criar apps que funcionam sem internet.
- ✓Evitar que dados se corrompam quando o app é usado em vários lugares ao mesmo tempo.
Exemplo do que pedir para a IA
“Salve as informações do usuário neste app.”
Quer saber mais? Abra as seções abaixo.
Como usar
O jeito mais fácil: copie a mensagem abaixo e cole no Claude, ChatGPT, Cursor ou outra IA. Ela lê a skill e segue as instruções.
Link da skill
Mensagem pronta para colar
Como funciona
Ele usa uma técnica chamada 'atores' que garante que apenas uma parte do código mexa nos dados por vez. Assim, evita confusão e erros. Os dados ficam na memória para serem rápidos e são salvos em um arquivo para segurança.
Instalação
Jeito mais fácil: copie o link da skill e cole no Claude, ChatGPT ou Cursor pedindo para seguir as instruções.
No terminal (Claude Code, Codex, Cursor), na pasta do projeto:
npx skills add affaan-m/ECC --skill swift-actor-persistenceOu baixe só o arquivo:
curl -L https://raw.githubusercontent.com/affaan-m/ECC/main/pi/core/skills/swift-actor-persistence/SKILL.md -o SKILL.mdConteúdo técnico (SKILL.md)
Tradução do texto original do autor no GitHub. Os comandos e códigos estão como no original.
Swift Actors para Persistência Thread-Safe
Padrões para construir camadas de persistência de dados thread-safe usando actors do Swift. Combina cache em memória com armazenamento em arquivo, aproveitando o modelo de actors para eliminar data races em tempo de compilação.
Quando Ativar
- Construindo uma camada de persistência de dados em Swift 5.5+
- Necessidade de acesso thread-safe a estado mutável compartilhado
- Desejo de eliminar sincronização manual (locks, DispatchQueues)
- Construindo apps offline-first com armazenamento local
Padrão Central
Repositório Baseado em Actor
O modelo de actors garante acesso serializado — sem data races, imposto pelo compilador.
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)
// Synchronous load during init (actor isolation not yet active)
self.cache = Self.loadSynchronously(from: fileURL)
}
// MARK: - Public API
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: - Private
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) })
}
}
Uso
Todas as chamadas são automaticamente async devido ao isolamento do actor:
let repository = LocalRepository<Question>()
// Read — fast O(1) lookup from in-memory cache
let question = await repository.find(by: "q-001")
let allQuestions = await repository.loadAll()
// Write — updates cache and persists to file atomically
try await repository.save(newQuestion)
try await repository.delete("q-001")
Combinando com 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()
}
}
Principais Decisões de Design
| Decisão | Racional |
|---|---|
| Actor (não classe + lock) | Thread safety imposta pelo compilador, sem sincronização manual |
| Cache em memória + persistência em arquivo | Leituras rápidas do cache, escritas duráveis no disco |
| Carregamento síncrono em init | Evita complexidade de inicialização async |
| Dicionário com chave por ID | Consultas O(1) por identificador |
Genérico sobre Codable & Identifiable |
Reutilizável em qualquer tipo de modelo |
Escritas atômicas em arquivo (.atomic) |
Previne escritas parciais em caso de crash |
Melhores Práticas
- Use tipos
Sendablepara todos os dados que cruzam limites de actors - Mantenha a API pública do actor mínima — exponha apenas operações de domínio, não detalhes de persistência
- Use escritas
.atomicpara prevenir corrupção de dados se o app travar no meio de uma escrita - Carregue síncronamente em
init— inicializadores async adicionam complexidade com benefício mínimo para arquivos locais - Combine com ViewModels
@Observablepara atualizações reativas da UI
Anti-Padrões a Evitar
- Usar
DispatchQueueouNSLockem vez de actors para novo código de concorrência Swift - Expor o dicionário de cache interno para chamadores externos
- Tornar o URL do arquivo configurável sem validação
- Esquecer que todas as chamadas de método de actor são
await— os chamadores devem lidar com o contexto async - Usar
nonisolatedpara contornar o isolamento do actor (anula o propósito)
Quando Usar
- Armazenamento de dados local em apps iOS/macOS (dados do usuário, configurações, conteúdo em cache)
- Arquiteturas offline-first que sincronizam com um servidor posteriormente
…
Perguntas frequentes
Por que usar 'atores' em vez de métodos normais?
Atores garantem que o código que mexe nos dados seja executado um de cada vez, de forma automática. Isso evita erros complicados de 'corrida de dados' que acontecem quando várias partes tentam mudar a mesma coisa ao mesmo tempo.
O que é 'persistência'?
Persistência significa guardar informações de forma que elas não se percam quando o aplicativo é fechado ou reiniciado. É como salvar um documento no computador.
Como os dados são salvos?
Os dados são guardados em um arquivo no formato JSON. Eles são salvos de forma 'atômica', o que significa que a escrita é feita de uma vez só, protegendo contra corrupção se o app travar durante o salvamento.
Detalhes
Descrição original do autor
Thread-safe data persistence in Swift using actors — in-memory cache with file-backed storage, eliminating data races by design. Use when persisting data in Swift and a data race or thread-safety problem needs designing out.
repo: affaan-m/ECC
Popularidade
- Estrelas no GitHub
- 280 mil
- Posição no ranking
- #124
- Licença
- MIT
- Atualizada em
- 15/10/2026
Comentários
- …
Mais skills deste repositório
accessibility
Ajuda seu agente a criar interfaces que todos possam usar. Garante que sites e aplicativos funcionem bem para pessoas com deficiência, como cegos ou com mobilidade reduzida.
affaan-m/ECC
agent-architecture-audit
Faz seu agente verificar se tudo está funcionando corretamente. Ele encontra e conserta problemas em sistemas de IA, garantindo que funcionem como esperado.
affaan-m/ECC
agent-eval
Ajuda seu agente a comparar diferentes ferramentas de programação de IA. Ele mede qual é mais rápido, barato e confiável para realizar tarefas específicas.
affaan-m/ECC
agent-harness-construction
Faz seu agente entender melhor como realizar tarefas. Ele otimiza as ferramentas e instruções que o agente usa para aumentar suas chances de sucesso.
affaan-m/ECC
Skills parecidas
api-and-interface-design
Ajuda a criar APIs e interfaces bem definidas. É útil ao projetar como diferentes partes de um software vão se comunicar.
addyosmani/agent-skills
mason
Ajuda seu agente a escrever código limpo e funcional. Ele segue as regras definidas para garantir que tudo funcione como esperado.
sickn33/agentic-awesome-skills
max
Faz seu agente melhorar o código existente sem mudar o que ele faz. Ele deixa o código mais fácil de ler e manter.
sickn33/agentic-awesome-skills