Why Realm "to many" relationship having always the same reference?

Why is the realm-list containing the very same elements instead of different ones ?

As you can see in the picture below, there are two relam-objects (UndoMemoryNameEntry and NameEntry). The first one contains a list of 8 elements. The list's element-type is of type NameEntry !

My last NameEntry object is written with currentScorePlayer=1 and currentScoreMe=15 as you can see in the picture below:

The list in UndoMemoryNameEntry is correctly inserted the last NameEntry object. You find the insertion-code further down... But now the problem: Why are all the existing list-elements as well changed to the newest inserted element ???? As you can see in the picture below, all the elements are unfortunately identical to the last one added - why ??????

If I change the NameEntry to the following :

And inserting at index=0 to the list, then the List changes to :

Why are all the elments changed ? And not just the inserted one ??? Thanks for any help on this !

My two realm-objects are :

class NameEntry: Object {
    dynamic var playerName = ""
    dynamic var isMyAdversary: Bool = false
    dynamic var currentScorePlayer: Int = 0
    dynamic var currentScoreMe: Int = 0
}

and the List :

class UndoMemoryNameEntry: Object {
    dynamic var undoPlayerName = ""
    let NameEntryList = List<NameEntry>()
}

The following code creates the Realm-List :

// query rlm for existing object (with name adversary
let undoPredicate = NSPredicate(format: "undoPlayerName == %@", adversaryName)
let undoPlayerName = rlm.objects(UndoMemoryNameEntry).sorted("undoPlayerName", ascending: true).filter(undoPredicate)
// if undoPlayerName object does not exist - then create it!
if (undoPlayerName.count < 1) {
    rlm.beginWrite()
    let undoEntry = UndoMemoryNameEntry()
    undoEntry.undoPlayerName = adversaryName
    rlm.add(undoEntry)
    rlm.commitWrite()
}

The following code adds a "NameEntry"-Element in the List :

let undoPredicate = NSPredicate(format: "undoPlayerName == %@", plaNameLab)
let undoPlayerName = rlm.objects(UndoMemoryNameEntry).sorted("undoPlayerName", ascending: true).filter(undoPredicate)
if (undoPlayerName.count == 1) {                    
    rlm.beginWrite()
    println(entry)
    var undoEntry = undoPlayerName[0] as UndoMemoryNameEntry
    undoEntry.NameEntryList.insert(entry, atIndex: 0)
    rlm.commitWrite()
}

The above code-excerts work perfectly - except that the realm-List always changes all its elements to the one just inserted.

Answers


I finally found a solution:

First of all rearrange the two realm objects as follows:

class NameEntry: Object {
    dynamic var playerName = ""
    dynamic var currentScorePlayer: Int = 0
    dynamic var currentScoreMe: Int = 0

    // the undo-list is better placed in the first object...
    let undoEntryList = List<UndoMemoryNameEntry>()

    override static func primaryKey() -> String? {
        return "playerName"
    }
}

class UndoMemoryNameEntry: Object {
    dynamic var undoPlayerName = ""
    dynamic var currentScorePlayer: Int = 0
    dynamic var currentScoreMe: Int = 0

    // no primary key here since the undoEntry will have several items with the same undoPlayerName
}

Then when adding a "NameEntry"-Element in the List :

let predicate = NSPredicate(format: "playerName == %@", plaNameLab)
let playerName = rlm.objects(NameEntry).sorted("playerName", ascending: true).filter(predicate)
if (playerName.count == 1) {                    
    rlm.beginWrite()
    var entry = playerName[0] as NameEntry

    // you need to create a new list object first !!!!!!!!!!!!
    // ...in my initial example, this creation was missing !!!!!!
    var siblingEntry = UndoMemoryNameEntry()

    siblingEntry.undoPlayerName = plaNameLab
    siblingEntry.currentScorePlayer = entry.currentScorePlayer
    siblingEntry.currentScoreMe = entry.currentScoreMe

    // insert new list-element
    entry.undoEntryList.insert(siblingEntry, atIndex: 0)

    // alternatively choose append if you want to add the element at the end of the list
    entry.undoEntryList.append(siblingEntry)

    // or choose the "ringbuffer-solution" given in the add-on below if you want to restrict the number of list-elements to ringbuffer-size !
    // ...

    rlm.commitWrite()
}

Add-on: If you want to create a ringbuffer having only a limited number of list-elements:

// create ringbuffer of 20 elements (20th element will be newest)
let ringBufferSize = 20
let undoPredicate = NSPredicate(format: "undoPlayerName == %@", plaNameLab)

if (entry.undoEntryList.filter(undoPredicate).sorted("undoPlayerName").count < ringBufferSize) {

    entry.undoEntryList.append(siblingEntry)
}
else {

    // entry.undoEntryList.replace(ringBufferSize-1, object: siblingEntry)
    entry.undoEntryList.removeAtIndex(ringBufferSize-1)
    entry.undoEntryList.append(siblingEntry)

    for index in 0..<ringBufferSize-1 {
        let tempEntry1 = rlm.objects(UndoMemoryNameEntry).filter(undoPredicate).sorted("undoPlayerName")[index] as UndoMemoryNameEntry
         let tempEntry2 = rlm.objects(UndoMemoryNameEntry).filter(undoPredicate).sorted("undoPlayerName")[index+1] as UndoMemoryNameEntry
         tempEntry1.currentScorePlayer = tempEntry2.currentScorePlayer
         tempEntry1.currentScoreMe = tempEntry2.currentScoreMe
     }

     let tempEntry = rlm.objects(UndoMemoryNameEntry).filter(undoPredicate).sorted("undoPlayerName")[ringBufferSize-1] as UndoMemoryNameEntry
     rlm.delete(tempEntry)
 }

Need Your Help

Android issue when switching from browser to app via intent filter

android android-intent

I have an application that starts up with a login activity, which redirects the user to a browser in order to authenticate to a service (has to be done via the browser, can't use a REST API or curl...

Scala: Button in Table Cell does not "fire" Action

scala scala-swing

I've got a little Problem: I want to have Buttons in some of the cells of my Table. As rendering component I return a Button with the following code: (theres application specific and debugging code...