按值分配变量,而不是参考

时间:2017-08-14 04:34:08

标签: swift

在没有引用其内存位置的情况下,对class而不是struct变量进行复制的最佳方法是什么。

例如

    class Person {
        var name: String = ""
        var age: Int = 0

        init(name: String, age: Int) {
            self.name = name
            self.age = age
        }

        var mapped: [String: Any] {
            return [
                "name": self.name,
                "age": self.age
            ]
        }
    }

    var person: Person = Person(name: "Hitchhiker", age: 42)

    var personCopy = person

    var dictionary: [String: Any] {
        return [
            "a_person": person.mapped,

            "c_personCopy": personCopy.mapped
        ]
    }

    print("Original:", dictionary.jsonStringValue)

    person.age = 100
    person.name = "Guide"

    print("\n\n========\n\n")
    print("Edit 1:", dictionary.jsonStringValue)

    personCopy.age = 200
    personCopy.name = "To the Galaxy"

    print("\n\n========\n\n")
    print("Edit 2:", dictionary.jsonStringValue)

// I have this swift extension to make my logs better, don't mind the implicit unwrapping.
extension Dictionary {
    var jsonStringValue: String {
        let jsonData = try! JSONSerialization.data(withJSONObject: self, options: .prettyPrinted)
        return String(data: jsonData, encoding: String.Encoding.utf8)!
    }
}

这会打印一个如下所示的输出。

Original: {
  "a_person" : {
    "name" : "Hitchhiker",
    "age" : 42
  },
  "c_personCopy" : {
    "name" : "Hitchhiker",
    "age" : 42
  }
}


========


Edit 1: {
  "a_person" : {
    "name" : "Guide",
    "age" : 100
  },
  "c_personCopy" : {
    "name" : "Guide",
    "age" : 100
  }
}


========


Edit 2: {
  "a_person" : {
    "name" : "To the Galaxy",
    "age" : 200
  },
  "c_personCopy" : {
    "name" : "To the Galaxy",
    "age" : 200
  }
}

如果我操纵副本的值,原件也会更新,因为副本是通过引用分配的。

我知道我可以创建类似于扩展函数的东西,它会生成原始变量的copy,就像这样。

extension Person {
    func copy() -> Person {
        return Person(name: self.name, age: self.age)
    }
}

var person = Person(name: "Jon Snow", age: 0)
var personCopy = person.copy()
personCopy.name = "Jon Targaryen" // this is now a value copy.

但是,如果不为许多不同的模型创建大量的样板代码,我怎么能这样做呢?

更新

我知道我可以在这里使用 Swift Protocols ,例如

protocol Copying {
    init(original: Self)
}

extension Copying {
    func copy() -> Self {
        return Self.init(original: self)
    }
}

我在这个answer中看到了,但是我必须将我的Model类子类化为这些,这可能会导致一些问题,因为我的Model已经是一个子类,它希望我实现一些这些样板< strong>初始化程序,我不想要那个

1 个答案:

答案 0 :(得分:2)

类是引用类型。获取副本的唯一方法是定义copy方法,或者创建一个init方法,该方法需要复制另一个实例(与copy基本相同法)。

只要您不需要继承,就应该考虑将模型类设为struct而不是class。然后你会自动获得复制语义。