Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing copy() in Swift

Tags:

swift

I want to be able to copy a custom class in Swift. So far, so good. In Objective-C I just had to implement the NSCopying protocol, which means implementing copyWithZone.

As an example, I have a basic class called Value which stores a NSDecimalNumber.

func copyWithZone(zone: NSZone) -> AnyObject! {     return Value(value: value.copy() as NSDecimalNumber) } 

In Objective-C I, could easily just call copy to copy my object. In Swift, there seems to be no way to call copy. Do I really need to call copyWithZone even if no zone is needed? And which zone do I need to pass as a parameter?

like image 488
rusty1s Avatar asked Jun 16 '14 11:06

rusty1s


People also ask

How do you implement a copy-on-write in Swift?

Swift arrays implement copy-on-write optimization, which means if we create an array and simply assign it to another variable (without any of the variables modifying the array), both the arrays will share the same reference to the underlying data.

How do I make a deep copy in Swift?

We can create a deep copy of the reference type using the copy() method. According to the documentation, copy() — Returns the object returned by copy(with:) . This is a convenience method for classes that adopt the NSCopying protocol.

How do you copy a struct in Swift?

The best way I have found is to write an initializer method that takes an object of the same type to "copy", and then has optional parameters to set each individual property that you want to change. The optional init parameters allow you to skip any property that you want to remain unchanged from the original struct.

What is difference between shallow copy and deep copy in IOS?

A deep copy duplicates the objects referenced while a shallow copy duplicates only the references to those objects. So if object A is shallow-copied to object B, object B refers to the same instance variable (or property) that object A refers to.


2 Answers

The copy method is defined in NSObject. If your custom class does not inherit from NSObject, copy won't be available.

You can define copy for any object in the following way:

class MyRootClass {     //create a copy if the object implements NSCopying, crash otherwise      func copy() -> Any {         guard let asCopying = ((self as AnyObject) as? NSCopying) else {             fatalError("This class doesn't implement NSCopying")         }          return asCopying.copy(with: nil)     } }  class A : MyRootClass {  }  class B : MyRootClass, NSCopying {      func copy(with zone: NSZone? = nil) -> Any {         return B()     } }   var b = B() var a = A()  b.copy()  //will create a copy a.copy()  //will fail 

I guess that copy isn't really a pure Swift way of copying objects. In Swift it is probably a more common way to create a copy constructor (an initializer that takes an object of the same type).

like image 138
Sulthan Avatar answered Oct 03 '22 22:10

Sulthan


Well, there is a really easy solution for this and you do not have to create root class.

protocol Copyable {     init(instance: Self) }  extension Copyable {     func copy() -> Self {         return Self.init(instance: self)     } } 

Now, if you want to make your custom class be able to copy, you have to conform it to Copyable protocol and provide init(instance: Self) implementation.

class A: Copyable {     var field = 0      init() {     }      required init(instance: A) {         self.field = instance.field     }  } 

Finally, you can use func copy() -> Self on any instance of A class to create a copy of it.

let a = A() a.field = 1 let b = a.copy() 
like image 32
Misternewb Avatar answered Oct 03 '22 21:10

Misternewb