【问题标题】:How can I properly copy objects from one Realm object to another object如何正确地将对象从一个领域对象复制到另一个对象
【发布时间】:2017-09-29 10:21:27
【问题描述】:

基于以下代码,我希望能够从现有代码创建一个新的ItemList。换句话说,我有一个名为First ListItemList,我想创建一个新的ItemList,将其命名为Second List,并用来自First ListItems 填充它。

我现在拥有它的方式是它按预期创建Second ListFirst List 中的Items 显示在Second List 中,但是当我只想删除Items 来自 First List,它从两个列表中删除 Items。我想我并没有真正复制这些项目。

所以问题是,我如何将Items 从First List 复制到Second List

对象模型:

class ItemList: Object {
    dynamic var listName = ""
    dynamic var createdAt = NSDate()
    let items = List<Item>()
}

class Item:Object{
    dynamic var productName:String = ""
    dynamic var createdAt = NSDate()
}

First List 创建Second List 的代码

这很好用,它创建 Second List 并添加来自 First List 的项目,但我不认为我在制作副本只是在 Second List 中显示它们。

        let newList = ItemList()
        newList.listName = "Second List"

        if let selectedList = realm.objects(ItemList.self).filter("listName = %@", "First List").first{
            let itemsFromFirstList = selectedList.items
            newList.items.append(objectsIn:itemsFromFirstList)
        }

        try! realm.write {
            realm.add(newList)
        }

这个代码应该只删除First List中的项目

这实际上删除了 First ListSecond List 中的项目

    let listToDelete = realm.objects(ItemList.self).filter("listName = %@", "First List").first

    try! realm.write {
        for item in (listToDelete?.items)! {
            realm.delete(realm.objects(Item.self).filter("productName = %@", item.productName).first!)

        }
    }

【问题讨论】:

    标签: ios swift realm


    【解决方案1】:

    你想做的是使用:

    for record in postsDB.objects(PostModel.self) {
        if !combinedDB.objects(PostModel.self).filter("postId == \(record.parentId)").isEmpty {
              combinedDB.create(PostModel.self, value: record, update: false)
        }
    }
    

    create方法继承自Object。它告诉目标创建一个新对象。如果您希望它查看那里是否已经有记录,请使用 true,如果有则更新它。 PostModel 是 Object 类型,record 是你要复制的。

    编辑:我添加了 if 语句以提供更多上下文。你没有显示你的类定义,所以我猜。这是一个工作示例。我从 DatabaseA 请求一组记录并将其复制到 DatabaseB(postsDB 到 combineDB)。

    因此,如果您尝试插入的对象类型是 List,我建议您定义 Object 的子类,并至少将所需的列表作为属性。

    class TagList: Object {
        dynamic var tag = ""
        var list = List<PostModel>()
    
        override class func primaryKey() -> String? {
            return "tag"
        }
    }
    

    完整的工作示例说明:创建新对象,将所有对象复制到第二个列表,复制后从第二个列表中删除,添加到第一个列表(没有从中删除任何内容。

    import Foundation
    import RealmSwift
    
    class Letter: Object {
        dynamic var letter = "a"
    }
    
    class Letters: Object {
        var letterList = List<Letter>()
    }
    
    class ListExample {
        let listRealmStore = try! Realm() // swiftlint:disable:this force_try
    
        func testThis() {
            print(Realm.Configuration.defaultConfiguration.fileURL!)
            listRealmStore.beginWrite()
            addSingleItems()  // add 3 objects to the DB
    
            let firstList = Letters()
            let allObjects = listRealmStore.objects(Letter.self)
            for item in allObjects {
                firstList.letterList.append(item)
            }
    
            let secondList = Letters()
            let itemsToCopy = firstList.letterList
            for item in itemsToCopy {
                let obj = listRealmStore.create(Letter.self)
                obj.letter = item.letter
                secondList.letterList.append(obj)
            }
    
            let third = Letter()
            third.letter = "Z"
            listRealmStore.add(third)
    
            firstList.letterList.append(third)
            secondList.letterList.removeLast()
            do {
                try listRealmStore.commitWrite()
            } catch let error {
                print("couldn't commit db writes: \(error.localizedDescription)")
            }
    
            print("list one:\n\(firstList)")
            print("list two:\n\(secondList)")
        }
    
        func addSingleItems() {
    
            for letter in ["a", "b", "c"] {
                let objectToInsert = Letter()
                objectToInsert.letter = letter
                listRealmStore.add(objectToInsert)
            }
        }
    }
    
    Results in:
    
    list one:
    Letters {
        letterList = List<Letter> (
            [0] Letter {
                letter = a;
            },
            [1] Letter {
                letter = b;
            },
            [2] Letter {
                letter = c;
            },
            [3] Letter {
                letter = Z;
            }
        );
    }
    list two:
    Letters {
        letterList = List<Letter> (
            [0] Letter {
                letter = a;
            },
            [1] Letter {
                letter = b;
            }
        );
    }
    

    【讨论】:

    • 我不确定我是否做得对,我尝试了newList.items.create(ItemList.self, value: itemsFromDefaultList, update: false),但我得到了错误Value of type 'List&lt;Item&gt;' has no member 'create' 谢谢。
    • 我认为你的 newList 是 Object 的子类,而不是列表。在这种情况下,我建议将列表放在对象的另一个子类中。我更新了示例。
    • @Mozahler - 抱歉,我对你的建议有点困惑。为了澄清任何误解,我想要的只是能够从现有的ItemList 创建一个新的。换句话说,我有一个名为First ListItemList,我想创建一个新的ItemList,将其命名为Second List,并用来自First ListItems 填充它。我使用First List 作为默认列表来创建新列表,所以最终第一和第二列表会有所不同。
    • 好的。我正在写一个完整的工作示例。我很快就会回来。
    • 查看下半部分(我保持原帖不变,但添加了一个完全有效的解决方案)。它创建新对象,将所有对象从第一个列表复制到第二个列表,复制后从第二个列表中删除最后一项,将新对象添加到第一个列表(没有从中删除任何内容)。
    【解决方案2】:

    您是真的想为您的项目创建副本,还是只是希望能够独立地将它们从列表中删除?

    当你这样做时:

    newList.items.append(objectsIn: itemsFromFirstList)
    

    您最终会在两个列表中看到 相同的对象List&lt;T&gt; 只存储对 Realm 中对象的引用。将对象附加到 List 只是引用现有对象,它不会复制对象。

    当您调用Realm.delete(_:) 时,您会将该对象完全从领域中删除,而不仅仅是从它所属的单个列表中删除。要从List 中删除对象,您应该改用List.remove(objectAtIndex:)

    【讨论】:

    • @ bdash - 非常感谢您提供的好信息。我想我想复制它们,因为每个ItemList 中的Items 需要相互独立,我知道我可能最终在多个ItemLists 中得到相同的Item,但这没关系。跨度>
    【解决方案3】:

    您正在寻找的解决方案的一部分可能是这样,在列表中复制对象,或者您可以使用这个想法自行克隆整个列表:

    以前回答过here

    截至 2020 年 12 月,此问题尚无适当的解决方案。不过我们有很多解决方法。

    这是我一直在使用的,我认为限制较少的一个。

    1. 使您的领域模型对象类符合可编码的要求
    class Dog: Object, Codable{
        @objc dynamic var breed:String = "JustAnyDog"
    }
    
    1. 创建这个帮助类
    class RealmHelper {
        //Used to expose generic 
        static func DetachedCopy<T:Codable>(of object:T) -> T?{
           do{
               let json = try JSONEncoder().encode(object)
               return try JSONDecoder().decode(T.self, from: json)
           }
           catch let error{
               print(error)
               return nil
           }
        }
    }
    
    1. 当您需要 Realm 对象的分离/真正的深层副本时调用此方法,如下所示:
     //Suppose your Realm managed object: let dog:Dog = RealmDBService.shared.getFirstDog()
     guard let detachedDog = RealmHelper.DetachedCopy(of: dog) else{
        print("Could not detach Note")
        return
     }
    //Change/mutate object properties as you want
     detachedDog.breed = "rottweiler"
    

    如您所见,我们使用 Swift 的 JSONEncoder 和 JSONDecoder,使用 Codable 的强大功能,无论我们的领域对象下有多少嵌套对象,都可以进行真正的深度复制。只需确保所有 Realm 模型类都符合 Codable。

    虽然它不是理想的解决方案,但它是最有效的解决方法之一。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-07
      • 1970-01-01
      • 2022-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-02
      相关资源
      最近更新 更多