How can I easily duplicate/copy an existing realm object

Solution 1:

In my case i just wanted to create an object and not persist it. so segiddins's solution didn't work for me.

Swift 3

To create a clone of user object in swift just use

let newUser = User(value: oldUser);

The new user object is not persisted.

Solution 2:

You can use the following to create a shallow copy of your object, as long as it does not have a primary key:

realm.create(ObjectType.self, withValue: existingObject)

Solution 3:

As of now, Dec 2020, there is no proper solution for this issue. We have many workarounds though.

Here is the one I have been using, and one with less limitations in my opinion.

  1. Make your Realm Model Object classes conform to codable
class Dog: Object, Codable{
    @objc dynamic var breed:String = "JustAnyDog"
}
  1. Create this helper class
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. Call this method whenever you need detached / true deep copy of your Realm Object, like this:
 //Suppose your Realm managed object: let dog:Dog = RealmDBService.shared.getFirstDog()
 guard let detachedDog = RealmHelper.DetachedCopy(of: dog) else{
    print("Could not detach Dog")
    return
 }
//Change/mutate object properties as you want
 detachedDog.breed = "rottweiler"

As you can see we are piggy backing on Swift's JSONEncoder and JSONDecoder, using power of Codable, making true deep copy no matter how many nested objects are there under our realm object. Just make sure all your Realm Model Classes conform to Codable.

Though its NOT an ideal solution, but its one of the most effective workaround.

Solution 4:

I had a similar issue and found a simple workaround to get a copy of a realm object. Basically you just need to make the object conform to the NSCopying protocol, something like:

import RealmSwift
import Realm
import ObjectMapper

class Original: Object, NSCopying{
   dynamic var originalId = 0
   dynamic var firstName = ""
   dynamic var lastName = ""

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

init(originalId: Int, firstName: String, lastName: String){
    super.init()

    self.originalId = originalId
    self.firstName = firstName
    self.lastName = lastName
}

func copy(with zone: NSZone? = nil) -> Any {
    let copy = Original(originalId: originalId, firstName: firstName, lastName: lastName)

    return copy
}
}

then you just call the "copy()" method on the object:

class ViewController: UIViewController {
   var original = Original()
   override func viewDidLoad() {
       super.viewDidLoad()

       var myCopy = original.copy()
   }
}

The nice thing about having a copy is that I can modify it without having to be in a realm write transaction. Useful when users are editing some data but didn't hit save yet or simply changed their mind.