Search code examples
iosswiftrealm

Realm not persisting changes made in write


I have a function where I am passing a payment and a debt object (both are structs representing the data in my Realm database). I then want to append the payment to the paymentHistory of the debt. Here is the code I use for this:

static func savePayment(payment: Payment, forDebt debt: Debt) throws {
  let realm = try Realm()
  let predicate = NSPredicate(format: "created = %@", debt.created)
  guard let dbDebt = realm.objects(DBDebt.self).filter(predicate).first else { fatalError("no debt found in DB for payment") }
  let dbPayment = DBPayment(payment: payment)
  try realm.write {

    // first try
    // dbDebt.paymentHistory.append(dbPayment)

    // second try
    let newPaymentHistory = dbDebt.paymentHistory
    newPaymentHistory?.append(dbPayment)
    dbDebt.paymentHistory = newPaymentHistory
  }
}

Note that I am including the code for the two attempts I've made, neither of which actually persisted the data (I checked this using the Realm Browser).

Also note that when debugging, I can see that the DBPayment has been created and was properly appended to the dbDebt's list. Maybe I am missing something obvious, but I expect this to work because in the Realm documentation, they state the following:

enter image description here

For reference, here are the definitions my structs and DB objects:

class DBDebt: Object {

  dynamic var amount: Double = 0.0
  dynamic var owner: DBPerson? = DBPerson()
  var paymentHistory: List<DBPayment>? = List<DBPayment>()
  dynamic var currency: String = Currency.Dollar.rawValue
  dynamic var created: NSDate = NSDate()
  dynamic var deadline: NSDate? = nil

  init(debt: Debt) {
    self.amount = debt.amount
    self.owner = DBPerson(person: debt.owner)
    self.paymentHistory = debt.paymentHistory.reduce(List<DBPayment>()) { (list: List<DBPayment>, payment: Payment) in
      list.append(DBPayment(payment: payment))
      return list
    }
    self.currency = debt.currency.rawValue
    self.created = debt.created
    self.deadline = debt.deadline
    super.init()
  }

  required init(value: AnyObject, schema: RLMSchema) {
    super.init(value: value, schema: schema)
  }

  required init(realm: RLMRealm, schema: RLMObjectSchema) {
    super.init(realm: realm, schema: schema)
  }

  required init() {
    super.init()
  }

}

class DBDebt: Object {

  dynamic var amount: Double = 0.0
  dynamic var owner: DBPerson? = DBPerson()
  var paymentHistory: List<DBPayment>? = List<DBPayment>()
  dynamic var currency: String = Currency.Dollar.rawValue
  dynamic var created: NSDate = NSDate()
  dynamic var deadline: NSDate? = nil

  init(debt: Debt) {
    self.amount = debt.amount
    self.owner = DBPerson(person: debt.owner)
    self.paymentHistory = debt.paymentHistory.reduce(List<DBPayment>()) { (list: List<DBPayment>, payment: Payment) in
      list.append(DBPayment(payment: payment))
      return list
    }
    self.currency = debt.currency.rawValue
    self.created = debt.created
    self.deadline = debt.deadline
    super.init()
  }

  required init(value: AnyObject, schema: RLMSchema) {
    super.init(value: value, schema: schema)
  }

  required init(realm: RLMRealm, schema: RLMObjectSchema) {
    super.init(realm: realm, schema: schema)
  }

  required init() {
    super.init()
  }

}


struct Payment {

  init(amount: Double, paymentDate: NSDate = NSDate()) {
    self.amount = amount
    self.paymentDate = paymentDate
  }

  let amount: Double
  let paymentDate: NSDate

}

class DBPayment: Object {

  dynamic var amount: Double = 0.0
  dynamic var paymentDate: NSDate = NSDate()

  init(payment: Payment) {
    self.amount = payment.amount
    self.paymentDate = payment.paymentDate
    super.init()
  }

  required init(value: AnyObject, schema: RLMSchema) {
    super.init(value: value, schema: schema)
  }

  required init(realm: RLMRealm, schema: RLMObjectSchema) {
    super.init(realm: realm, schema: schema)
  }

  required init() {
    super.init()
  }

}

Solution

  • In order to persist objects in realm you have to call the add() function on your realm (docs).

    The following should work:

    try realm.write {
    
      // this persists your dbPayment in your realm!
      realm.add(dbPayment)
    
      // first try
      // dbDebt.paymentHistory.append(dbPayment)
    
      // second try
      let newPaymentHistory = dbDebt.paymentHistory
      newPaymentHistory?.append(dbPayment)
      dbDebt.paymentHistory = newPaymentHistory
    }