Swift Making Copies of Passed Class Instances

Swift making copies of passed class instances

Wrote the following (with the help of a friend) in playground:

protocol Copyable {
func copyOfValues() -> AnyObject
}

extension Copyable where Self: NSObject {
func copyOfValues() -> AnyObject{
var copyOfOriginal = Self()
let mirror = Mirror(reflecting: self)
for (label, value) in mirror.children {
if let label = label {
copyOfOriginal.setValue(value, forKey: label)
}
}

return copyOfOriginal
}
}

class Test: NSObject, Copyable {
var a = 1
var b = 2
}

var test = Test()
var copy = test.copyOfValues() as! Test

print(dump(test))
print(dump(copy))
copy.a = 10
print(dump(test))
print(dump(copy))

This is a nice and simple function so that I can obtain copy of my class instances in swift. In swift, since they are a reference type (and I am not sure if you can dereference it or whatnot) you would basically have to write a custom copy function for your objects every time. Well, Now I wrote this, so as long as you are using a subclass of NSObject and use this protocol, you'll be fine.

This has worked exactly as I need in my code

Swift, when referencing a class property, is it making a copy of the data?

Yes and yes. It doesn't matter that the String and the Int were in a class. You asked for the String or the Int (or both), those are value types, you got copies.

It's easy to prove this to yourself, especially with the String. Just change something about it, and then look back at what the class instance is holding: it will be unchanged.

class C {
var stringProperty : String
init(string:String) {
self.stringProperty = string
}
}
let c = C(string:"hello")
var s = c.stringProperty
s.removeLast()
print(s) // hell
print(c.stringProperty) // hello

If you want to see the class-as-reference in action, make two of the same instance and do something to one of those:

class C {
var stringProperty : String
init(string:String) {
self.stringProperty = string
}
}
let c = C(string:"hello")
let d = c
c.stringProperty = "goodbye"
print(d.stringProperty) // goodbye

Are swift classes inside struct passed by copy during assignment?

Passed by reference. You can test it. Declare:

class A{}
struct B { let a = A()}

then:

let b = B()
print("A = \(unsafeAddressOf(b.a))")//0x0000600000019450
let b_copy = b
print("A = \(unsafeAddressOf(b_copy.a))")//0x0000600000019450

Class vs. Struct in Swift (copying)

Why in the class declaration does it change the firstMessage object. Are they the same objects?

The example you gave is a really nice one because it succinctly illustrates the difference between class and struct, and you came about this close -> <- to answering your own question, even if you didn't realize it. As the other answers have explained, class creates a reference type, which means that when you assign an instance of a class to a variable, that variable gets a reference to the object, not a copy of it. You said so yourself:

//if I assign, its a reference to the original instance
var secondMessage = firstMessage

In your example, firstMessage and secondMessage are really references to the one object that you created. This kind of thing is done all the time in object oriented languages because it's often important to know that you're dealing with a specific object and not a copy, especially if you might want to make changes to that object. But that also brings danger: if your code can get a reference to an object and change it, so can some other code in the program. Shared objects that can be changed create all kinds of headaches when you start writing multithreaded code. When you added text to secondMessage, firstMessage also changed because both variables refer to the same object.

Changing the declaration of Message to struct makes it a value type, where assignment (for example) creates a new copy of the object in question instead of a new reference to the same object. When you added text to secondMessage after changing Message to a struct, the assignment secondMessage = firstMessage created a copy of firstMessage, and you only changed that copy.

Is this a rule that if I assign a new object from the old object?

Whether your assignment creates a copy of the object or a reference to it depends, as you've shown, on whether the thing being assigned has reference semantics (class) or value semantics (struct). So you need to be aware of the difference, but most of the time you don't need to think too hard about it. If you're dealing with an object where you don't care about the object's identity and are mainly concerned with its contents (like a number, string, or array), expect that to be a struct. If you care about which object you're dealing with, like the front window or the current document, that'll be a class.

Then I would have to declare secondMessage = Message() to make it a new instance.

Right -- if Message is a class, assigning one to a new variable or passing it into a method won't create a new one. So again, are you more likely to care about which message you're dealing with, or what is in the message?

How to pass entire Swift class instance to another class, while using a third party ViewController/class?

I dont know if this is the right way of doing but I hope it may solve your problem, create another class with a static instance of variable viewController as follows:

import UIKit

class DataStore {
static var controller: UIViewController?
}

then store the instance of viewController in controller variable as follows in ViewController class:

 DataStore.controller = self

later in class Z you can access the view controller instance as follows:

DataStore.controller

How to do Deep Copy in Swift?

Deep Copy

Your example is not a deep copy as discussed on StackOverflow. Getting a true deep copy of an object would often require NSKeyedArchiver

Swift and copying

The NSCopying protocol is the Objective-C way of providing object copies because everything was a pointer and you needed a way of managing the generation of copies of arbitrary objects. For an arbitrary object copy in Swift you might provide a convenience initializer where you initialize MyObject another MyObject and in the init assign the values from the old object to the new object. Honestly, that is basically what -copy does in Objective-C except that it usually has to call copy on each of the sub-objects since Objective-C practices defensive copying.

let object = MyObject()
let object2 = MyObject(object)

Almost everything is pass-by-value. Almost.

However, in Swift almost everything is pass-by-value (you should really click the aforementioned link) so the need for NSCopying is greatly diminished. Try this out in a Playground:

var array = [Int](count: 5, repeatedValue: 0)
print(unsafeAddressOf(array), terminator: "")
let newArray = array
print(unsafeAddressOf(newArray), terminator: "")
array[3] = 3
print(array)
print(newArray)

You can see that the assignment is not a copy of the pointer but actually a new array. For a truly well-written discussion of the issues surrounding Swift's non-copy-by-value semantics with relation to structs and classes I suggest the fabulous blog of Mike Ash.

Finally, if you want to hear everything you need to know from Apple you can watch the WWDC 2015 Value Semantics video. Everyone should watch this video, it really clears up the way memory is handled within Swift and how it differs from Objective-C.



Related Topics



Leave a reply



Submit