4

I am quite new in Swift. And I create a class(for example):

class Fraction{
    var a: Int
    init(a:Int){
        self.a = a
    } 
    func toString() -> String{
        return "\(self.a)"
    }
}

and I also build a in other class function:

class func A_plusplus(f:Fraction){
    f.a++
}

Then in the executive class I write:

var object = Fraction(a:10)
print("before run func = " + object.toString())
XXXclass.A_plusplus(object)
print("after ran func =" + object.toString() )

So the console output is

before run func = 10; after ran func =11

The question is how can I just send a copy of the "object" to keep its value which equal to 10

And if functions are always pass-by-reference, why we still need the keyword: "inout"

what does difference between A_plusplus(&object)//[if I make the parameter to be a inout parameter] and A_plusplus(object)

Universally, I don't want to use struct. Although this will solve my problem exactly, I do pass-by-value rarely.So I don't want program's copying processes slow my user's phone down :(

And It seems conforming the NSCopying protocol is a good option.But I don't know how to implement the function: func copyWithZone(zone: NSZone)-> AnyObject? correctly

Microos
  • 1,728
  • 3
  • 17
  • 34

3 Answers3

6

If your class is subclass of NSObject,better to use NSCopying

class Fraction:NSObject,NSCopying{
var a:Int
var b:NSString?
required init(a:Int){
    self.a = a
}
func toString() -> String{
    return "\(self.a)"
}
func copyWithZone(zone: NSZone) -> AnyObject {
    let theCopy=self.dynamicType.init(a: self.a)
    theCopy.b = self.b?.copy() as? NSString
    return theCopy
}
}
class XXXclass{
class func A_plusplus(f:Fraction){
    f.a++
    f.b = "after"
}

}

var object = Fraction(a:10)
object.b = "before"
print("before run func = " + object.toString())
print(object.b!) //“Before”

XXXclass.A_plusplus(object.copy() as! Fraction)
print("after ran func =" + object.toString() )
print(object.b!)//“Before”

If it is just a common swift class,You have to create a copy method

class Fraction{
var a: Int
init(a:Int){
    self.a = a
}
func toString() -> String{
    return "\(self.a)"
}
func copy()->Fraction{
    return Fraction(a: self.a)
}
}
class XXXclass{
    class func A_plusplus(f:Fraction){
        f.a++
   }
}
var object = Fraction(a:10)
print("before run func = " + object.toString())
XXXclass.A_plusplus(object.copy())
print("after ran func =" + object.toString() )

To make it clear,you have to know that there are mainly two types in swift

  1. Reference types. Like Class instance,function type
  2. Value types,Like struct and others(Not class instance or function type)

If you pass in a Reference types,you pass in the copy of Reference,it still point to the original object.

If you pass in a Copy type,you pass in the copy of value,so it has nothing to do with the original value

Let us talk about inout,if you use it,it pass in the same object or value.It has effect on Value type

func add(inout input:Int){
    input++
}

var a = 10
print(a)//10
add(&a)
print(a)//11
Leo
  • 24,596
  • 11
  • 71
  • 92
  • 1
    thank you! this is a brilliant solution! And I think I am good with what I always consider :D – Microos Oct 16 '15 at 07:33
  • This is good but I would prefer to use NSCopying (it's some ridiculous to make copy function) – Alex Oct 16 '15 at 08:02
  • If using `NSCopying`,then have to make it subclass of NSObject.It is not suit for Swift Class – Leo Oct 16 '15 at 08:04
  • can i just neglect the NScopying.To build a copy() function which assigns a new object with exactly same properties ? – Microos Oct 16 '15 at 09:15
  • If your class is subclass of NSObject,you better to use `NScopying `,otherwise you can just make a copy function to return a new instance – Leo Oct 16 '15 at 09:18
  • It is the Subclass of NSObject. Because the NSCoding require to inherit NSObject. And I have to inherit the NSCopying. But I don't know how to Implement the only function in NSCopying protocol:[CopyWithZone(zone:NSzone) -> AnyObject? ] I put [return self in it ] but still workless.(I can't just assign the properties to a new Object , because, the properties are more complex than [a:Int].If I do so the new Object still has the reference to the old Object's properties ) – Microos Oct 16 '15 at 09:47
  • @Leo So Any properties also have to conform the NSCopying???btw,I can't invoke self.dynamicType.init – Microos Oct 16 '15 at 11:37
  • @Leo It seems so, I just let all the properties' class(They are all DIY data type, not elementary type ) get a copy( ) function. And them it finally works! – Microos Oct 16 '15 at 11:54
2

Swift has a new concept so called "struct"

You can define Fraction as struct (Not class)

And

struct Fraction{
   ...
}
var object = Fraction(a:10)
var object1 = object  //then struct in swift is value type, so object1 is copy of object (not reference)

And if you use struct then try to use inout in A_plusplus function Hope this will help you.

Alex
  • 616
  • 4
  • 11
  • 1
    thank you! i just notice that, but my class has quite big content, can i just change the (class) into (struct)? will anything goes well? – Microos Oct 16 '15 at 07:28
  • 1
    @Microos. https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html – joe Oct 16 '15 at 07:30
  • If you use class, then you should make your class conform NSCopying protocol And also you should use mutableCopy() function instead of direct assign then. – Alex Oct 16 '15 at 08:01
2

how can I just send a copy of the "object" to keep its value which equal to 10

In Swift classes and functions are always passed by reference. Structs, enums and primitive types are passed by value. See this answer.

You can't pass an object by value. You would have to manually copy it before passing it by reference (if that's what you really want).

Another way is to turn your class into a struct, since it would then be passed by value. However, keep in mind there a few other differences between classes and structs, and it might not necessarily be what you want.

And if functions are always pass-by-reference, why we still need the keyword: "inout"

According to the swift documentation, inout is used when

you want a function to modify a parameter’s value, and you want those changes to persist after the function call has ended, define that parameter as an in-out parameter instead.

So in practice with inout you can pass a value type (such as struct or primitive) by reference. You shouldn't really use this very often. Swift provides tuples, that could be used instead.

what does difference between A_plusplus(&object)//[if I make the parameter to be a inout parameter] and A_plusplus(object)

There is no difference for your A_plusplus function. In that function you don't modify the parameter f itself, you modify the f.a property.

The following example shows the effect of using inout when passing a class object. Both functions are the same, differing only in its parameter definition.

class Person {
    var name: String
    init(name: String) { self.name = name }
}

var me = Person(name: "Lennon") // Must be var to be passed as inout

// Normal object by reference with a var
func normalCall(var p: Person) {
    // We sure are able to update p's properties,
    // and they will be reflected back to me
    p.name = "McCartney"
    // Now p points to a new object different from me,
    // changes won't be reflected back to me
    p = Person(name: "Ringo")
}

// Inout object reference by value
func inoutCall(inout p: Person) {
    // We still can update p's properties,
    p.name = "McCartney"
    // p is an alias to me, updates made will persist to me
    p = Person(name: "Ringo")
}

print("\(me.name)") //--> Lennon

normalCall(me)
print("\(me.name)") //--> McCartney

inoutCall(&me)
print("\(me.name)") //--> Ringo

In normalCall p and me are different variables that happen to point to the same object. When you instantiate and assign a new object to p, they no longer refer to the same object. Hence, further changes to this new object will not be reflected back to me.

Stating that p is a var argument just means that its value can change throughout the function, it does not mean the new value will be assigned to what was passed as argument.

On the other hand, in inoutCall you can think of p and me as aliases. As such, assigning a new object to p is the exact same as assigning a new object to me. Any and every change to p is persisted in me after the function ends.

Community
  • 1
  • 1
Edman
  • 5,335
  • 29
  • 32
  • thank you! I think I learn things more deeply! But I would not going to use struct, because in most situation in my proj, I use the past by reference. So always copy value will make it to be less efficient – Microos Oct 16 '15 at 07:40
  • in the function 1 , why assigning a newPerson(Ringo)is work less. I think function are assigning a different reference to "me" – Microos Oct 16 '15 at 09:44
  • I have added further explanation about the example code with `var` and `inout` in the answer. – Edman Oct 16 '15 at 10:03
  • Very nice example! – Aviram Netanel Nov 30 '22 at 07:17