Como depurar problemas de sync do CloudKit usando o Console.app

O problema
Cenário: um app multi-plataforma (macOS + iOS) usando SwiftData com CloudKit sync. Tudo funciona perfeitamente no iPhone. No Mac, o sync está completamente quebrado:
- Tarefas editadas no Mac não sincronizam
- Pastas criadas no Mac nunca chegam ao CloudKit
- Nenhum erro visível no app
O app não apresenta crashes nem mensagens de erro. Do ponto de vista do usuário, simplesmente "não funciona".
Console.app: a ferramenta esquecida
O macOS inclui uma ferramenta poderosa para diagnóstico que muitos desenvolvedores ignoram: o Console.app (/Applications/Utilities/Console.app).
Como usar
- Abra o Console.app
- Na barra lateral, selecione seu Mac
- No campo de busca, filtre pelo nome do seu app
- Reproduza o problema no app
- Observe os logs em tempo real
O que procurar
Erros de CloudKit aparecem com prefixos como:
CoreData+CloudKitCKSchedulerCKContainer
Descobrindo a causa raiz
Ao filtrar os logs pelo nome do app, encontrei o erro:
"Cannot create or modify field 'CD_dueDate' in record 'CD_Folder' in production schema"
O problema ficou claro: o schema de produção do CloudKit estava desatualizado. O modelo Folder possuía uma propriedade dueDate adicionada após o schema original ter sido enviado para produção.
CloudKit não migra automaticamente schemas em produção. Resultado: 399 operações de sync falharam silenciosamente.
Solução manual: atualizar o schema
A correção imediata requer acesso ao CloudKit Dashboard:
- Acessar icloud.developer.apple.com
- Selecionar o container do app
- Ir em Schema -> Record Types -> CD_Folder
- Adicionar o campo
CD_dueDate(tipo: Date/Time) - Clicar em Deploy Schema Changes
Após reiniciar o app, o sync voltou a funcionar.
O problema recorrente
A solução manual resolve o problema pontual, mas não evita recorrências. Toda vez que um novo campo é adicionado ao modelo Swift, o mesmo problema pode ocorrer.
CloudKit só cria colunas no schema quando recebe registros com esses campos preenchidos. Adicionar propriedades aos modelos Swift não atualiza automaticamente o schema do CloudKit.
Solução automatizada: schema seeding
Criei uma ferramenta de debug que força a criação das colunas no CloudKit. A ideia é simples:
- Criar registros temporários com todos os campos preenchidos
- Salvar no contexto (força CloudKit a criar as colunas)
- Aguardar sync
- Remover os registros de teste
- Fazer deploy do schema para produção
# if DEBUG
enum CloudKitSchemaSeed {
@MainActor
static func seedSchema(context: ModelContext) throws {
let folder = Folder(
title: "__SCHEMA_SEED_FOLDER__",
color: "#FF0000",
startDate: Date(),
customIconSymbolName: "star.fill"
// ... todos os campos
)
context.insert(folder)
try context.save()
}
}
# endif
A ferramenta fica disponível apenas em builds de debug, acessível via Settings -> Developer.
Descoberta: campos _ckAsset
Durante os testes, um novo erro apareceu no Console.app:
"Cannot create or modify field 'CD_taskDescriptionData_ckAsset' in record 'CD_Task' in production schema"
CloudKit converte automaticamente campos Data maiores que 1MB para Assets. Quando isso acontece, cria um campo adicional com sufixo _ckAsset.
Se esse campo não existe no schema de produção, o sync falha.
Solução
O seed deve incluir dados grandes para forçar a criação do campo Asset:
private static func createLargeData() -> Data {
let chunk = "Schema seed data for CloudKit asset field creation. "
let repeatedString = String(repeating: chunk, count: 40_000) // ~2MB
return Data(repeatedString.utf8)
}
// No seed:
task.taskDescriptionData = createLargeData()
Checklist de verificação
Após corrigir problemas de schema:
- Editar item no Mac -> verificar propagação para iPhone
- Editar item no iPhone -> verificar propagação para Mac
- Criar novo item no Mac -> verificar se aparece no iPhone
- Deletar item no Mac -> verificar se some do iPhone
Lições aprendidas
-
Console.app é essencial para diagnosticar problemas em apps de produção. Erros que o app não exibe para o usuário ficam visíveis nos logs do sistema.
-
CloudKit não migra schemas automaticamente em produção. Mudanças no modelo de dados requerem deploy manual ou uso de ferramentas de seeding.
-
Campos Data grandes viram Assets. Se o app pode armazenar dados maiores que 1MB, o campo
_ckAssetcorrespondente deve existir no schema. -
Sync funcionar em um dispositivo não garante funcionamento em outro. O iPhone tinha o schema correto; o Mac estava tentando criar campos que não existiam em produção.
Referências
Posts Relacionados
Como melhorar a performance de drag-and-drop em apps macOS
Aprenda como otimizar a performance de drag-and-drop em apps macOS trocando desenho manual por propriedades de CALayer aceleradas por GPU.
CoreData: debug: WAL checkpoint - O que significa esse log?
Explicação técnica sobre os logs 'CoreData: debug: WAL checkpoint: Database did checkpoint' que aparecem durante operações com CoreData e SwiftData no iOS e macOS.
Drag and Drop no macOS: Como Evitar Drop Zones Competindo Entre Si
Guia completo sobre implementação de drag and drop em macOS com AppKit. Aborda o problema de drop zones competindo, centralização de drop handling, coordenadas non-flipped do NSView, e como mostrar drop indicators entre itens.