swift - 为什么 Realm "to many"关系总是有相同的引用?

标签 swift one-to-many realm

为什么 realm-list 包含完全相同的元素而不是不同的元素?

如下图所示,有两个 relam-objects(UndoMemoryNameEntry 和 NameEntry)。第一个包含 8 个元素的列表。列表的元素类型是 NameEntry 类型!

enter image description here

我的最后一个 NameEntry 对象是用 currentScorePlayer=1 和 currentScoreMe=15 编写的,如下图所示:

enter image description here

UndoMemoryNameEntry 中的列表正确地插入了最后一个NameEntry 对象。您会在更下方找到插入代码... 但现在的问题是:为什么所有现有的列表元素也都更改为最新插入的元素????正如您在下图中看到的,不幸的是,所有元素都与最后添加的元素相同 - 为什么?????

enter image description here

如果我将 NameEntry 更改为以下内容:

enter image description here

并在 index=0 处插入到列表中,然后列表变为:

enter image description here

为什么所有元素都变了?而不仅仅是插入的那个???感谢您对此的任何帮助!

我的两个 Realm 对象是:

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

和列表:

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

以下代码创建 Realm 列表:

// 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()
}

以下代码在列表中添加一个“NameEntry”元素:

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()
}

上面的代码摘录工作得很好——除了 realm-List 总是将它的所有元素更改为刚刚插入的元素。

最佳答案

我终于找到了解决办法:

首先将两个 Realm 对象重新排列如下:

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
}

然后在列表中添加“NameEntry”元素时:

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()
}

附加组件:如果你想创建一个只有有限数量的列表元素的环形缓冲区:

// 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)
 }

关于swift - 为什么 Realm "to many"关系总是有相同的引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31221718/

相关文章:

ios - 如何从 Realm 数据库中读取单列数据?

objective-c - Throwing 方法不能是@objc 协议(protocol)的成员,因为它返回类型为 'Bool' 的值

ios - UIImageView 更新在触摸事件发生后才绘制

Android机房一对多关系

JPA @OneToMany 不获取 child

ios - 迁移 Realm 中的主键

swift - 设置 translatesAutoresizingMaskIntoConstraints = false 创建多个立即被取消初始化的对象

ios - 如何在 Swift 中循环访问 UITableView 中的数据

jquery - 一对多的图像

node.js - 将本地数据库的数据合并到Mongodb的远程数据库