我已经创建了多个类,所有这些都需要实现NSCopying协议,但是在我的类中有很多属性,是否有更简单的方法?下面是我目前的方式:
class TestA: NSObject, NSCopying {
var a: CGFloat = 0
var b: CGFloat = 0
required override init() {
}
func copy(with zone: NSZone? = nil) -> Any {
let item = type(of: self).init()
item.a = a
item.b = b
return item
}
}
class TestB: TestA {
var c: CGFloat = 0
var d: CGFloat = 0
override func copy(with zone: NSZone? = nil) -> Any {
let item = super.copy(with: zone) as! TestB
item.c = c
item.b = b
return item
}
}
我的想法是,我们可以采取类的所有属性,自动创建一个新对象,赋值给新对象吗?
使用初始化器
class TestA: NSObject, NSCopying {
var a: CGFloat = 0
var b: CGFloat = 0
required override init() {}
convenience init(a: CGFloat, b: CGFloat) {
self.init()
self.a = a
self.b = b
}
func copy(with zone: NSZone? = nil) -> Any {
let item = TestA(a: a, b: b)
return item
}
}
这样做并不能真正节省代码,因为你仍然需要一个初始化器来接受所有属性的值,但你确实得到了一个简化的copy
方法和另一个初始化器,在其他情况下也可能有用。
你可以看看使用KeyValueCoding
协议的KeyValueCoding包,它实现了对象的所有属性的枚举,并通过键路径为纯swift类和结构设置值。
在此基础上可以实现Copying
协议:
protocol Copying: KeyValueCoding {
init()
}
extension Copying {
func makeCopy() -> Self {
var item = Self()
var _self = self
metadata.properties.forEach {
item[$0.name] = _self[$0.name]
}
return item
}
}
工作原理:
class TestA: Copying {
var a: CGFloat = 1
var b: Int = 2
required init() {}
}
class TestB: TestA {
let c: String = "Hello Copy!"
let d: Date = Date(timeIntervalSince1970: 123456789)
}
let objectA = TestA()
objectA.a = 100
objectA.b = 200
let copiedA = objectA.makeCopy()
print(copiedA.a) // "100.0"
print(copiedA.b) // "200"
let objectB = TestB()
objectB.a = 100
objectB.b = 200
let copiedB = objectB.makeCopy()
print(copiedB.a) // "100.0"
print(copiedB.b) // "200"
print(copiedB.c) // "Hello Copy!"
print(copiedB.d.timeIntervalSince1970) // "123456789.0"
所以你可以看到这种方法也适用于继承属性。
struct MyStruct: Copying {
let a = 1.0
let b = 2
let c = "c"
}
let myStruct = MyStruct()
let copied = myStruct.makeCopy()
print(copied) // MyStruct(a: 1.0, b: 2, c: "c")
我想我已经找到了一个解决方案,但我不确定这是否会有任何不良影响。谁能告诉我这是怎么了。谢谢!
@objcMembers class TestA: NSObject, NSCopying {
var a: CGFloat = 0
var b: CGFloat = 0
var c: CGFloat = 0
required override init() {
}
func copy(with zone: NSZone? = nil) -> Any {
let item = type(of: self).init()
for property in getAllPropertys() {
let value = self.value(forKey: property)
item.setValue(value, forKey: property)
}
return item
}
func getAllPropertys()->[String]{
var result = [String]()
var count:UInt32 = 0
let proList = class_copyPropertyList(object_getClass(self),&count)
for i in 0..<numericCast(count) {
let property = property_getName((proList?[i])!);
let proper = String.init(cString: property)
result.append(proper)
}
return result
}
}