iCloudManager é um pacote Swift projetado para facilitar o uso do CloudKit em seus aplicativos iOS. A classe genérica CloudManager simplifica o processo de interagir com o CloudKit, permitindo operações CRUD (Criar, Ler, Atualizar e Deletar) em registros do iCloud de forma mais intuitiva.
- iOS 15.0 ou superior.
- Xcode 13 ou superior.
- Seu projeto deve estar configurado para usar o CloudKit e possuir as permissões adequadas no portal do desenvolvedor da Apple.
Adicione o iCloudManager ao seu projeto usando o Swift Package Manager:
- No Xcode, vá em File > Add Packages...
- Insira o repositório do
iCloudManager. - Selecione a versão desejada e adicione o pacote ao seu projeto.
O primeiro passo é garantir que o tipo que você deseja salvar no CloudKit conforme com o protocolo CloudStorable. Isso significa que você precisa implementar os métodos fromCKRecord e toCKRecord para mapear suas propriedades para um CKRecord.
import CloudKit
public protocol CloudStorable {
static func fromCKRecord(_ record: CKRecord) -> Self?
func toCKRecord() -> CKRecord
func isSameAs(_ other: Self) -> Bool
}Crie uma instância de CloudManager passando o seu tipo que conforma com CloudStorable:
let manager = CloudManager<MyData>()Para salvar um novo item no CloudKit:
manager.saveItem(newItem) { result in
switch result {
case .success(let savedItem):
print("Item salvo com sucesso: \\(savedItem)")
case .failure(let error):
print("Erro ao salvar item: \\(error.localizedDescription)")
}
}Para buscar todos os itens:
manager.fetchItems { result in
switch result {
case .success(let items):
print("Itens recuperados: \\(items)")
case .failure(let error):
print("Erro ao buscar itens: \\(error.localizedDescription)")
}
}Você também pode utilizar um NSPredicate para filtrar os resultados:
let predicate = NSPredicate(format: "age > %d", 18)
manager.fetchItems(withPredicate: predicate) { result in
// ...
}Para atualizar um item existente:
manager.updateItem(updatedItem) { result in
switch result {
case .success(let item):
print("Item atualizado: \\(item)")
case .failure(let error):
print("Erro ao atualizar item: \\(error.localizedDescription)")
}
}Para deletar um item:
manager.deleteItem(itemToDelete) { result in
switch result {
case .success():
print("Item deletado com sucesso.")
case .failure(let error):
print("Erro ao deletar item: \\(error.localizedDescription)")
}
}Se você tem relacionamentos entre registros, pode utilizar o protocolo Relatable e os métodos fornecidos para salvar pais com seus filhos:
manager.saveParentWithChildren(parent: parentItem, children: childItems) { result in
// ...
}E para buscar filhos de um pai:
manager.fetchChildrenForParent(parent: parentItem) { result in
// ...
}Aqui está um exemplo de como definir uma estrutura que conforma com CloudStorable:
import CloudKit
struct MyData: CloudStorable {
var id: CKRecord.ID
var name: String
var age: Int
// Conformidade com CloudStorable
static func fromCKRecord(_ record: CKRecord) -> MyData? {
guard let name = record["name"] as? String,
let age = record["age"] as? Int else {
return nil
}
return MyData(id: record.recordID, name: name, age: age)
}
func toCKRecord() -> CKRecord {
let record = CKRecord(recordType: "MyData", recordID: id)
record["name"] = name as CKRecordValue
record["age"] = age as CKRecordValue
return record
}
func isSameAs(_ other: MyData) -> Bool {
return self.id == other.id
}
}Se você tem relacionamentos, como um pai com filhos:
struct ChildData: Relatable {
var id: CKRecord.ID
var name: String
var parentRef: CKRecord.Reference?
// Conformidade com CloudStorable
static func fromCKRecord(_ record: CKRecord) -> ChildData? {
guard let name = record["name"] as? String else {
return nil
}
let parentRef = record["parentRef"] as? CKRecord.Reference
return ChildData(id: record.recordID, name: name, parentRef: parentRef)
}
func toCKRecord() -> CKRecord {
let record = CKRecord(recordType: "ChildData", recordID: id)
record["name"] = name as CKRecordValue
if let parentRef = parentRef {
record["parentRef"] = parentRef
}
return record
}
func isSameAs(_ other: ChildData) -> Bool {
return self.id == other.id
}
}let manager = CloudManager<MyData>()let newItem = MyData(
id: CKRecord.ID(recordName: UUID().uuidString),
name: "John Doe",
age: 30
)
manager.saveItem(newItem) { result in
switch result {
case .success(let savedItem):
print("Item salvo com sucesso: \\(savedItem)")
case .failure(let error):
print("Erro ao salvar item: \\(error.localizedDescription)")
}
}manager.fetchItems { result in
switch result {
case .success(let items):
print("Itens recuperados: \\(items)")
case .failure(let error):
print("Erro ao buscar itens: \\(error.localizedDescription)")
}
}var itemToUpdate = existingItem
itemToUpdate.name = "Jane Doe"
manager.updateItem(itemToUpdate) { result in
switch result {
case .success(let updatedItem):
print("Item atualizado: \\(updatedItem)")
case .failure(let error):
print("Erro ao atualizar item: \\(error.localizedDescription)")
}
}manager.deleteItem(itemToDelete) { result in
switch result {
case .success():
print("Item deletado com sucesso.")
case .failure(let error):
print("Erro ao deletar item: \\(error.localizedDescription)")
}
}Salvar um pai com seus filhos:
let parentItem = MyData(
id: CKRecord.ID(recordName: UUID().uuidString),
name: "Parent Item",
age: 50
)
let childItem1 = ChildData(
id: CKRecord.ID(recordName: UUID().uuidString),
name: "Child 1",
parentRef: nil
)
let childItem2 = ChildData(
id: CKRecord.ID(recordName: UUID().uuidString),
name: "Child 2",
parentRef: nil
)
manager.saveParentWithChildren(parent: parentItem, children: [childItem1, childItem2]) { result in
switch result {
case .success():
print("Pai e filhos salvos com sucesso.")
case .failure(let error):
print("Erro ao salvar pai e filhos: \\(error.localizedDescription)")
}
}Buscar os filhos de um pai:
manager.fetchChildrenForParent(parent: parentItem) { (result: Result<[ChildData], Error>) in
switch result {
case .success(let children):
print("Filhos recuperados: \\(children)")
case .failure(let error):
print("Erro ao buscar filhos: \\(error.localizedDescription)")
}
}- Extensibilidade: A classe
CloudManageré projetada para ser extensível. Você pode personalizá-la conforme necessário para atender às necessidades específicas do seu aplicativo. - Tratamento de Erros: Todos os métodos fornecem feedback através de closures de conclusão com um
Result, permitindo que você trate erros de maneira robusta. - Assincronicidade: As operações com o CloudKit são assíncronas. Certifique-se de lidar adequadamente com essa característica em sua interface de usuário.
- Verificação do iCloud: A classe verifica automaticamente o status da conta iCloud do usuário. Se o iCloud não estiver disponível ou configurado, a propriedade
iCloudOkseráfalse. - Permissões: Certifique-se de ter as permissões adequadas e de configurar o CloudKit corretamente no portal do desenvolvedor da Apple e no seu projeto.
- Teste: Lembre-se de testar todas as operações em diferentes cenários para garantir a robustez e a confiabilidade da sua implementação.