【问题标题】:Insert object in RLMArray property on already persisted object?在已经持久化的对象上的 RLMArray 属性中插入对象?
【发布时间】:2014-10-14 20:17:42
【问题描述】:

我正在尝试使用 Realm 解决一个相当简单直接的问题。我有在它们(线程)上具有数组属性的对象。当我通过我们的 API 获取所有线程时,它们都被持久化到 Realm 中,因为父对象被单独保存,因此数组属性中的所有子对象(消息和用户)也被正确持久化。但是在应用程序的生命周期中,我需要将新消息添加到该数组属性中。这是我正在尝试做的事情:

func addPubNubMessageToThread(notification: NSNotification) {
    if let info = notification.userInfo as? Dictionary<String, AnyObject> {

        var embeddedMessage = Message(json: (info["data"] as? NSDictionary)!)

        let threadId = (info["thread"]! as String)

        // Persist the message to Realm for future use
        var respectiveThread = Thread(forPrimaryKey: threadId)
        let realm = RLMRealm.defaultRealm()
        realm.beginWriteTransaction()
        respectiveThread.conversation.insertObject(embeddedMessage, atIndex: UInt(0)) // Always fails here in XCode with the error below
        realm.addOrUpdateObject(respectiveThread)
        realm.commitWriteTransaction()
    }
}

但每次我得到以下错误:

 *** Terminating app due to uncaught exception 'RLMException', reason: 'Setting unique property '_id' with existing value '540729b543dd5d1868a42b5d''

更多上下文,这里是我的 Realm 模型:

class Message: RLMObject {
    dynamic var _id = ""
    dynamic var type = ""
    dynamic var text = ""
    dynamic var author = User()
    dynamic var created = NSDate()
    dynamic var lastUpdated = NSDate()
}

class Thread: RLMObject {
    dynamic var _id = ""
    dynamic var name = ""
    dynamic var conversation = RLMArray(objectClassName: Message.className())
    dynamic var participants = RLMArray(objectClassName: User.className())
    dynamic var created = NSDate()
    dynamic var lastUpdated = NSDate()
}

class User: RLMObject {
    dynamic var _id = ""
    dynamic var name = ""
    dynamic var firstName = ""
    dynamic var lastName = ""
    dynamic var email = ""
    dynamic var phone = ""
    dynamic var username = ""
    dynamic var avatar = NSData()
    dynamic var created = NSDate()
    dynamic var lastUpdated = NSDate()
}

每条消息都有一个名为 author 的属性,它所抱怨的 _id 是消息作者(或用户对象)的 _id。错误信息很难解读。我认为这是说我正在尝试使用已经存在的主键创建一个新的用户对象。如果这是问题所在,我应该怎么做才能将新的 Realm 对象添加到已持久化对象的数组属性中?

编辑

我正在为每个模型设置主键,如下所示:

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

_id 是由 MongoDB 生成的 GUID...所以它是全球唯一的。

【问题讨论】:

  • 是的,这就是该消息的含义。不过,您似乎实际上并没有将 _id 作为您的主键(这是通过覆盖类方法 primaryKey 来完成的)。另请注意,主键在某个子类的所有对象中必须是唯一的,而不仅仅是数组中的对象。
  • 抱歉,您所说的“用户对象”指的是用户类的对象?在那种情况下,我认为这不是确切的问题,它看起来更像是各自的线程实例。
  • 查看我对描述主键、_id 的唯一性以及 XCode 抛出错误的行(实际上不是我 addOrUpdateObject 的行,而是我尝试插入的行)的编辑新消息放入数组属性)
  • 消息从何而来?我的意思是你确定它以前没有被添加过,也许是隐含的?
  • 它来自 NSNotificationCenter 发布的通知,没有其他地方可以保存它...它以 JSON websocket 有效负载的形式出现,然后我尝试将它们添加到线程中

标签: ios swift realm


【解决方案1】:

问题是调用的时候 insertObject 您的对象和所有子对象都是在 Realm 中创建的,而不是在它们已经存在时更新。如果您首先显式更新您的对象(这也适用于所有子对象),那么这应该可以避免这个问题:

var persistedMessage = realm.addOrUpdateObject(embeddedMessage)
respectiveThread.conversation.insertObject(persistedMessage, atIndex: UInt(0))

【讨论】:

    【解决方案2】:

    您的问题可能出在您的 Message(json:) 初始化程序中。当您处理消息的 JSON 时,我猜测作者 ID 已传递(可能还有其余的作者数据)。在您的初始化程序中,您可能正在实例化一个新用户,而不是获取领域中现有用户的实例。我重新创建了您的模型对象,然后创建了现有用户、线程和消息。我能够反序列化来自 JSON 的消息并将新消息添加到现有对话数组中,只要我的反序列化逻辑抓住了现有用户(如果提供的话)。这是我的示例初始化程序:

    init(json : NSDictionary) {
        self._id = json["_id"] as String
        self.type = json["type"] as? String ?? ""
        self.text = json["text"] as? String ?? ""
        self.created = json["created"] as? NSDate ?? NSDate()
        self.lastUpdated = json["lastUpdated"] as? NSDate ?? NSDate()
    
        if let author = json["author"] as? NSDictionary {
            if let authorId = author["_id"] as? String {
                self.author = User(forPrimaryKey: authorId)
            }
        }
    
        super.init()
    }
    

    在这种情况下,我的示例 JSON:

    {
        "_id": "2",
        "text": "new message", 
        "author": {"_id": "1"}
    }
    

    最后,读取 JSON 并添加到已保存线程的代码:

    var error: NSError?
    var jsonDictionary : NSDictionary!
    if let dictionary = NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.allZeros, error: &error) as? NSDictionary {
        jsonDictionary = dictionary
    } else {
        NSLog("\(error)")
        return
    }
    
    let realm = RLMRealm.defaultRealm()
    
    realm.beginWriteTransaction()
    
    let newMessage = Message(json: jsonDictionary)
    self.thread.conversation.addObject(newMessage)
    realm.addOrUpdateObject(self.thread)
    
    realm.commitWriteTransaction()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-24
      • 1970-01-01
      • 1970-01-01
      • 2017-10-10
      • 2021-11-07
      • 2011-11-28
      • 2013-06-04
      • 1970-01-01
      相关资源
      最近更新 更多