lukas
lukas

Reputation: 2410

Does Realm guarantee that queries always reflect the current state of the database, even within a write transaction?

Consider the following example:

class Item: Object {
    @objc dynamic var id: UUID = UUID()
    
    @objc dynamic var value: Int = 0
    
    override class func primaryKey() -> String? {
        return "id"
    }
}


let realm = try! Realm()

try! realm.write {
    let query1 = realm.objects(Item.self)
    precondition(query1.isEmpty)
    let newItem = Item()
    realm.add(newItem)
    precondition(query1.contains(newItem))

    let query2 = realm.objects(Item.self).filter("value == 12")
    precondition(query2.isEmpty)
    newItem.value = 12
    precondition(query2.count == 1 && query2[0] == newItem)
}

When running this program, I can observe that Realm does in fact live-update queries, and all of the preconditions pass.

My question is the following: is this behaviour guaranteed? I.e., does Realm guarantee that accessing a query will always return the current in-memory version of objects of that query's predicate (as long as you're on the same thread that created the query), even for changes that have not yet been committed to disk (by ending the write transaction)?

Note: I am asking only about the behaviour when manually accessing a query object (e.g., by checking its count or whether it contains some object, as done in the example above). I am NOT asking about the behaviour of observers, which obviously won't get called until the write transaction is actually committed.

Upvotes: 0

Views: 61

Answers (1)

Jay
Jay

Reputation: 35648

Background for completeness:

Realm writes are called transactional writes. Meaning once the transaction starts, you can freely read, write and modify data within the transaction and the transaction is a single indivisible operation.

The reads and writes within a transaction either all pass or all fail - if an exception is thrown within the transaction, the entire transaction is canceled and data is "rolled back" to pre-transaction

Answer:

All reads and writes within a transaction are synchronized to the transaction - if a query is generated within the write and data is written that conforms to that query, it will exist within the query results; that means reads reflect the current status of the data as it exists within the transaction.

Note that large transactions opened on the UI thread may appear to block the UI so best practice is to open them on a background thread. Writes are blocking so only do them on one thread at a time.

For example, suppose we have a PersonClass Object

realm.writeAsync {
    print("-- before write --")
    
    //generate a query
    let results = realm.objects(PersonClass.self)

    //output the current Persons
    for person in results {
        print(person.name)
    }
    
    print("--writing--")
    
    //add two more people
    let p = PersonClass(name: "Jay")
    realm.add(p)
    
    let j = PersonClass(name: "Cindy")
    realm.add(j)
    
    print("--done writing--")

    //output the results again; it will contain Jay and Cindy Person
    for person in results {
        print(person.name)
    }
}

Upvotes: 0

Related Questions