copy 关键字的作用
从一个例子说起:
@interface Person : NSObject @property (nonatomic, copy) NSString *name; @end Person *xiaohong = [[Person alloc] init];这段代码中
NSString为什么要加上copy关键字呢?
copy关键字的作用是,调用obj(已经遵从NSCoding)的copyWithZone:,并将返回值赋值给实例变量。
copy关键字的作用
深浅拷贝
上图说明了深浅拷贝的内存分配情况,不分配内存的情况下,将增加引用计数(
ARC)。
容易疑惑的地方:
- B2 为什么是浅拷贝
- C3 为什么不安全
- E2 为什么不安全
- D3 为什么不安全
不可变类型(以NSString为例)
NSString类比C++代码如下(未区分堆栈):
NSString *strOC = @"hello oc"; // 指针是可变的,但是所指的内存区域是不可变的
const char strC[] = "hello cpp"; // c++下类似的情况
strOC = @"new"; // strOC指向的区域发生变化
内存2
疑惑点1
形如
@property (copy) NSString *name; // Person中定义 xiaohong.name = [NSString stringWithFormat:@"xiaohong"];
在不可变类型的属性指定了copy关键字后,并没有分配新的内存,这是因为已经指定属性为不可变的类型,所以此块内存区域的值是不会发生变化,这是为了为节约内存和提高效率(分配回收内存需要时间)。
疑惑点2
考虑如下代码
@property (copy) NSString *name; // Person中定义 NSMutableString *name = [NSMutableString stringWithFormat:@"xiaohong"]; xiaohong.name = name; [name appendString:@" Zhang"]; NSLog(@"%@", xiaohone.name); // "xiaohong zhang"
这里说的不安全是因为在类中已经将name定义为NSString类型,所以说希望该内存是不可变的,但是又在外部修改了它的值,与期望相悖,而且用NSString的指向一个NSMutableNSString这也是不安全的。
疑惑点3
考虑如下代码
@property NSMutableString *name; // Person中定义 xiaohong.name = [NSString stringWithFormat:@"xiaohong"]; [xiaohone.name appendString:@" zhang"]; // crash
造成crash的原因为向NSString发送了appendString:的消息,但是NSString不能处理此消息。因为copy关键字调用copyWithZone:,生成的是不可变类型(即NSString),即使指针被转换为了NSMutableString类型,但是runtime会根据class中的信息发送消息。
copy 的作用如下
@property NSMutableString *name; // Person中定义 // setter中:self.name = [[NSString stringWithFormat:@"xiaohong"] copy]; // self.name实际是NSString类型 xiaohong.name = [NSString stringWithFormat:@"xiaohong"]; [xiaohone.name appendString:@" zhang"]; // crash
疑惑点4
@property (copy) NSMutableString *name; // Person中定义 // setter中:self.name = [[NSMutableString stringWithFormat:@"xiaohong"] copy]; // copy 产生的不可变对象NSString // self.name实际是NSString类型 xiaohong.name = [NSMutableString stringWithFormat:@"xiaohong"]; [xiaohone.name appendString:@" zhang"]; // crash, 因为name的类型是NSString
对于OC中容器类型的拷贝
容器类型的行为与OC中其他引用类型的行为是一致的。所以说如果容器中存放的是引用类型,则即使发生深拷贝,也只是拷贝了容器中的引用。所以说容器的深拷贝只是对容器来说的。
例如
NSMutableString *mStr = [NSMutableString stringWithFormat:@"xiaohong"]; NSMutableArray *mAry = [NSMutableArray arrayWithObject:mStr]; NSMutableArray *mCAry = mAry.mutableCopy; [mstr appendString: @" zhang"]; // mAry[0]与mCAry[0]指向相同内存 NSLog(mAry[0]); // "xiaohong zhang" NSLog(mCAry[0]); // "xiaohong zhang"
copy和mutableCopy属性将分别调用copyWithZone:和mutableCopyWithZone:
把自定义的类作为有copy关键字的属性
需要实现copyWithZone:,如果自定义的类包含可变和不可变两种类型,则需要分别实现copyWithZone:和mutableCopyWithZone:,copy的行为是自己定义的,当然正常情况下应该是定义为深拷贝。











网友评论