Realm中的嵌套对象更新问题

时间:2017-08-18 10:42:54

标签: ios swift realm

请检查以下TeamMember的模型类。在团队中,members可以包含Member列表。 JSON对象用于在服务方法中创建和更新团队。会员可以单独更新。在Member对象中,有一个属性lastSeenAt,根据该成员的活动进行更新。

class Team: Object {
  dynamic var channelId: String? = nil
  dynamic var title: String? = nil
  let members = List<Member>()

  override class func primaryKey() -> String? {
    return "channelId"
  }
}

class Member: Object {
  dynamic var _id: String?
  dynamic var lastSeenAt: Date?
  override class func primaryKey() -> String? {
    return "_id"
  }
}

服务方法更新团队和成员

func createAndUpdateTeams(_ teams: [[String:Any]]?) {

  DispatchQueue(label: "queueNameToCreate", attributes: []).async {          
      let realm = try! Realm()

      try! realm.write({ () in
        for team in teams! {
          realm.create(Team.self, value: team, update: true)
        }
      })
  }
}

func updateMember(_ member: [String:Any]?) {

  DispatchQueue(label: "queueNameToUpdateMember", attributes: []).async {
      let realm = try! Realm()

      try! realm.write({
        realm.create(MemberRealm.self, value: member, update: true)
      })
  }
}

要获得团队的实时更新,我在Results<Team>添加了一个通知块,如下所示:

teams = realm.objects(Team.self);
notificationToken = teams?._addNotificationBlock({ [weak self](changes) in
  switch( changes ) {
  case .initial:
    self?.tableView?.reloadData()
  case .update(_,let deletions,let insertions,let modifications):
    print("Modified: deletions: \(deletions.count),\n insertions: \(insertions.count),\n modifications:\(modifications.count)")
    self?.tableView?.reloadData()
  case .error:
    break
  }
})

问题

当我调用updateMember(_:)来更新Member对象时,会调用通知块。虽然团队中没有更新,但TableView会使用相同的数据加载自身。作为效果,屏幕会针对每个updateMember(_:)来电波动。

Github Sample Project生成问题 https://github.com/milankamilya/RealmUpdateTest

1 个答案:

答案 0 :(得分:1)

您看到的是Realm的预期行为。即使只有一个对象在完成块范围内的一个对象的一对多关系中更新,也会通过设计调用通知块。由于您的Team类与Member具有一对多关系,因此在所有Team个对象上设置通知块时,通知块将在每次调用时调用如果Member对象存储在您的Team个对象members属性中,则会对其进行更新。

请参阅this GitHub问题更详细地解释了该问题。

您可以使用的一种解决方法是将members定义为LinkingObjects而不是List。我自己没有尝试过,但根据链接的GitHub问题的答案,当一个对象发生变化时,通知块不会被调用LinkingObjects,而使用的是一对多关系List

要将LinkingObjects用作members,您需要按以下方式更改模型类:

class Team: Object {
    dynamic var channelId: String? = nil
    dynamic var title: String? = nil
    let members = LinkingObjects(fromType: Member.self, property: "team") //finds all Member objects, where Member.team = self (this team)

    override class func primaryKey() -> String? {
        return "channelId"
    }
}

class Member: Object {
    dynamic var _id: String?
    dynamic var team:Team?
    dynamic var lastSeenAt: Date?
    override class func primaryKey() -> String? {
        return "_id"
    }
}