Hi,SwiftGG 翻译组启用了新的域名:swiftgg.team今后翻译组的各项活动将会在新域名下开展,不要错过哦!

今天我们来介绍一下@NSCopying

copy关键字和NSCopying协议

在介绍@NSCopying之前,我们首先来回顾一下 Objective-C 中与之相关一些知识点。首先是copy关键字。相信大家在初学 Objective-C 时, 会去理解copyretainassign等常用到的关键字。这几个关键字对应着赋值时候内存分配,理解起来也比较简单。这篇文章讲的比较详细,这里只说说copy关键字的作用。

copy关键字的作用,基本就是字面意思:生成新的对象,并且对内容进行拷贝。举一个NSString 的例子:

//声明copy属性的
@property (nonatomic, copy) NSString *copyedString;

//使用可变字符串对copyedString进行赋值
NSMutableString *string = [NSMutableString stringWithFormat:@"test"];
self.copyedMString = string;
NSLog(@"origin string: %p, %p", string, &string);
NSLog(@"copyed string: %p, %p", _copyedString, &_copyedString);

输出结果:

strong string: 0x7fddc060b460, 0x7fddc0698600
copy string: 0xa000000747365744, 0x7fddc0698608

可以看到,赋值以后的copyedString已经是一个与string不相关的字符串。这就是所谓的深拷贝,地址和内容都赋值了一份。实际应用中,我们还会用到strong这个关键字,关于copystrong的区别和联系。可以阅读文章最后的参考资料和 stackoverflow 相关问题展开阅读。

实际上,使用copy关键字修饰的类必须遵循NSCopying协议才能在赋值时候进行深拷贝或者浅拷贝(是深拷贝还是浅拷贝取决于该协议的实现方法- (id)copyWithZone:(NSZone *)zone)。IOS开发之深拷贝与浅拷贝(mutableCopy与Copy)详解说到了如何理解和实现深拷贝浅拷贝

@NSCopying

Swift 中的@NSCopying和 Objective-C 中的copy关键字类似。@NSCopying修饰的属性必须是遵循NSCopying协议的,而在 Swift 中, NSCopying协议被限制给类使用。由于 Swift 中的 String 类型已经是值类型了。所以 String 不能通过扩展遵循NSCopying协议。值类型的赋值,只可能是值的拷贝,当然,结构体里面有对象类型,就另当别论了。

以下是一个使用@NSCopying的案例:

class Foo : NSObject, NSCopying {
var bar = "bar"
var baz = 1
func copyWithZone(zone: NSZone) -> AnyObject {
let copy = Foo()
print("copyed")
copy.bar = bar
copy.baz = baz
return copy
}
}

class Test : NSObject {
@NSCopying private(set) var foo : Foo
init(foo : Foo) {
self.foo = foo
super.init()
}
}

var initialFoo = Foo()
initialFoo.bar = "initial"
initialFoo.baz = 0

let test = Test(foo: initialFoo)
test.foo.bar // "initial"
test.foo.baz // 0

var readFoo = Foo()
readFoo.bar = "new"
readFoo.baz = 0



test.foo = readFoo // 调用copyWithZone返回一个新的对象

initialFoo === readFoo // 2个对象不一样了

//readFoo变化了,但是test.foo没有变
readFoo.bar = "changed"
readFoo.baz = 100

test.foo.bar // "new"
test.foo.baz // 0

大部分情况下,@NSCopying在 Swift 中的使用场景都是放在调用 Objective-C 中的类型时候使用。自定义类去遵循NSCopying协议,不太符合 Swift 的类型体系:请使用结构体!

stackoverflow 相关问题整理

参考资料

文章目录
  1. 1. copy关键字和NSCopying协议
  2. 2. @NSCopying
  3. 3. stackoverflow 相关问题整理
  4. 4. 参考资料