Problème de Synchro des images avec CoreData + CloudKit

Bonjour,

Petite question (désolé je ne vais pas aider à la résolution du problème). J’ai une apps similaire mais pas avec du vin mais des BD ou des livres (c’est moins fun :slight_smile:) . On insère un livre et il est possible d’uploader une vignette de la couverture de la BD soit à partir de l’APN de l’iPhone/iPad soit à partir de la bibliothèque de l’appareil.

Le tout est sauvegardé de la même façon que toi via Core Data et syncro dans CloudKit.

Comme l’appli est en swiftui, je passe par un picker (UIViewControllerRepresentable) pour sélectionner les images avant de les sauvegarder dans CoreData (type de donnée Binary).
le taux de compression est à 0.5 en jpg

Mon problème est en production : la synchronisation ne se fait pas d’un appareil à un autre et semble même bloquer complètement toute la syncro; ce qui fait que les appareils ne sont pas à jour entre eux.
je n’ai aucun problème en développement : les deux simulateurs se synchronisent parfaitement et quasi instantanément.

Du coup, je ne vois pas trop où peut être le problème… Si quelqu’un à une idée (erreur dans la migration du schéma CloudKit peut être?)…

Merci d’avance pour votre aide dans ma réflexion.

Bon we.

Benjamin

Bonjour,

Est-ce qu’on peut voir le code en question?

Yes mais lequel ? :slight_smile:

voilà déjà le code du picker :

struct ImagePickerView: UIViewControllerRepresentable {

//MARK: Création des variables
@Binding var showingModal: Bool
@Binding var image: Data
var sourceType: UIImagePickerController.SourceType

func makeCoordinator() -> ImagePickerView.Coordinator {
    return ImagePickerView.Coordinator(child1: self)
}

func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePickerView>) -> UIImagePickerController {
    let picker = UIImagePickerController()
    picker.sourceType = self.sourceType
    picker.delegate = context.coordinator
    return picker
}

func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePickerView>) {
}

class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    var child : ImagePickerView
    
    init(child1: ImagePickerView) {
        child = child1
    }
    
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        self.child.showingModal.toggle()
    }
    
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        let image = info[.originalImage] as! UIImage
        let data = image.jpegData(compressionQuality: 0.5)
        
        self.child.image = data!
        self.child.showingModal.toggle()
    }
}

}

???
Tu parles d’un problème de synchronisation des fichiers, et tu montres le code d’un élément d’interface utilisateur !

C’est pas faux mais avant de montrer du code il faudrait déjà que j’ai une idée de l’endroit où est le problème… vu que je ne l’ai pas en développement mais seulement en production…:grimacing:

Montre nous comment tu récupères l’image et comment tu la mets dans un objet core data puis comment tu sauves la base core data.

Une idée comme ça de source possible de problème: un problème de thread pour le NSManagedObjectContext ? Mais, il peut sans doute y en avoir des dizaines !

Voilà le code.

@ObservedObject var book: Books

//MARK: Variables d'environnement
@Environment(\.managedObjectContext) var manager
@Environment(\.presentationMode) var presentationMode

//MARK: Autres variables
@State var image: Data = .init(count: 0)
@State var showingModal: Bool = false
@State var sourceType: UIImagePickerController.SourceType

//MARK: Affichage de la vue
var body: some View {
    NavigationView {
        
        VStack {
            
            if self.image.count != 0 {
                Image(uiImage: UIImage(data: self.image)!)
                    .renderingMode(.original)
                    .resizable()
                    .frame(width: 150, height: 250)
                
            } else {
                Image(systemName: "photo.fill").font(.system(size: 150)).foregroundColor(.gray)
                    .font(.system(size: 100))
                    .padding(20)
            }
            
            //Bouton pour choisir la caméra ou la bibliothèque
            HStack {
                Button(action: {
                        self.showingModal.toggle()
                        self.sourceType = .camera
                    
                }) {Text("Camera")}
                
                Text("/")
                
                Button(action: {
                        self.showingModal.toggle()
                        self.sourceType = .photoLibrary
                    
                }) {Text("Photo Library")}
            }
            
            if self.image.count != 0 {
                Button(action: {
                    self.book.image = self.image
            
                    try? self.manager.save()
                    self.presentationMode.wrappedValue.dismiss()
            
                }) { Text("Save Image").foregroundColor((self.image.count > 0) ? Color.orange : Color.gray)}
            }
        }
        .navigationBarTitle("Add Photo")

Bonsoir,

Une suggestion: remplacer le

try? self.manager.save()

par un

do {
try self.manager.save()
} catch {
//ajouter un log ou une alerte en cas d'erreur
}

ce qui te permettra de vérifier si ton image est bien enregistrée

Cordialement
Nicolas

Merci pour l’info.
Je viens de tester : pas d’erreur de log quand je teste sur le simulateur. donc a priori, la donnée s’enregistre bien dans CoreData.

par contre, coté prod, si je regarde les enregistrements que j’ai fait, le champ correspondant à l’image n’apparait pas dans CloudKit ce qui voudrait dire :

  • sur un terminal « physique » , Core Data n’enregistre pas. mais dans ce cas, pk ce qui marche sur le simulateur ne marcherait pas en vrai ?
  • entre deux terminaux « physiques », les données Core Data de l’un ne remontent pas vers iCloud et donc ne redescendent pas vers le deuxième terminal.

Et quand tu testes en production ?

En production ça ne va pas: aucune image ne remonte dans CloudKit et cela semble même bloquer la synchronisation des autres données (ou en tout cas ça l’a ralenti fortement).

Il faut que tu mettes un log pour voir s’il y a un message d’erreur au niveau du manager.save()

https://developer.apple.com/documentation/os/logger

Sinon, difficile d’imaginer ce qui se passe

Problème apparement résolu : il s’agissait plutôt d’une erreur de déploiement du schéma de données (les données relatives aux images manquaient dans le schéma de production) plutôt qu’une erreur de code.

Merci à tous pour votre aide

1 J'aime

Good ! Content pour toi