2017-09-17 4 views
0

J'ai quelques objets gérés par domaine dans mon application qui doivent conserver une trace de l'horodatage dans lequel ils ont été modifiés pour la dernière fois. J'aurais pu mettre en œuvre le modèle de programmation du référentiel pour cela, ou je pourrais juste me rappeler de définir la propriété chaque fois que je change quelque chose sur ces objets (ce qui est une idée de repli, aussi horrible que cela puisse paraître). Ce que j'ai fait est de créer un objet singleton qui surveille les collections d'objets pour lesquels je veux garder un horodatage de "dernière modification". Ceci est démarré au démarrage de l'application et garde un oeil sur les collections pour toutes les modifications.Éviter les notifications de modification récursques du domaine

Le « flux » général est:

  • attente de notification de changement
  • Le changement, boucle les indices modifiés
  • Vérifiez l'index existe avant d'essayer d'accéder à l'objet (au cas où)
  • realm.write une nouvelle date de dernière modification à l'objet

Comme vous pouvez le deviner probablement déjà (un nd comme je le soupçonnais), ce realm.write pour mettre à jour mon dernier horodatage modifié, puis crée une nouvelle notification de changement, qui à son tour rend la mise à jour d'horodatage à nouveau. Donc, il finit juste en boucle pour toujours après le premier changement.

Vous cherchez des options pour résoudre ce problème.

Voici ce que j'ai mis en œuvre:

class RealmCollectionLastModifiedMonitor { 
    static let shared = RealmCollectionLastModifiedMonitor() 

    private var formObjectNotificationToken: NotificationToken? 

    private init() { 
     startMonitoring() 
    } 

    deinit { 
     stopMonitoring() 
    } 

    func startMonitoring() { 
     let realm = try! Realm() 
     let caseforms = realm.objects(CaseForm.self) 

     formObjectNotificationToken = caseforms.addNotificationBlock { [weak self] (changes: RealmCollectionChange) in 
      switch changes { 

      case .initial: 
       // Do nothing for now - as i've not worked out what this is :P     
       break 

      case .update(_, let deletions, let insertions, let modifications): 

       // Some debug output 
       print("Form collection change: Deletions = \(deletions.count), Insertions = \(insertions.count), Modifications = \(modifications.count)") 

       // Loop the modificated indexes, get a reference to the form, then update the last modified timestamp 
       for i in modifications { 
        if caseforms.indices.contains(i) { 
         do { 
          try realm.write { 
           caseforms[i].lastModified = Date() 
          } 
         } catch { 
          print("Failed to update modified date") 
         } 
        } 
       } 

       break 

      case .error(let error): 
       // Do nothing for now - If a write fails, we could rollback, but it's not uber-important 
       break 
      } 
     } 
    } 

    func stopMonitoring() { 
     formObjectNotificationToken = nil 
    } 
} 

Répondre

2

Malheureusement, ma suggestion est une refactorisation de votre approche actuelle. Vous avez l'intention de ne pas surveiller les modifications générales apportées à la collection, mais plutôt de modifier des propriétés spécifiques sur des objets spécifiques. Avec ceci est le mien, je pense que vous serez bien mieux servi en surveillant chaque objet individuel, et cela vous permettra d'introspection dans les propriétés qui ont changé sur ledit objet.

Par exemple,

func monitor(_ caseForm: CaseForm) -> NotificationToken { 
    return caseForm.addNotificationBlock { change in 
     switch change { 
      case .change(let properties): 
       guard properties.count > 0 !properties.first(where: { $0.name == "lastModified" }) else { return } 
        // modify last modified date 
      case .deleted: 
       break 
      case .error(let error): 
       // handle error 
      } 
     } 
    } 
} 
+0

Merci James. Pensez-vous que cela pourrait être jumelé avec les notifications de collection pour insérer et supprimer? Donc, si j'ai un moniteur de collection pour supprimer et insérer, qui alors créer (ou supprimer) des notifications d'objet pour les objets individuels? Évidemment, j'ai aussi besoin d'enregistrer des notifications pour les objets existants au démarrage de l'application. J'essaierai demain, mais j'ai pensé que je poserais la question juste au cas où vous savez déjà que c'est une idée stupide et je ne devrais même pas l'essayer: P – TRG

+0

Oui, mais vous devez vous assurer que vous ajoutez un bloc de notification à l'objet en dehors du rappel de notification de collection. Une façon simple de le faire est simplement de faire un 'DispatchQueue.main.async {self.monitor (caseForm)}' dans le rappel de notification de collection. –

+0

Génial, n'aurait pas pensé à faire fonctionner le moniteur en dehors du bloc, merci James! – TRG