1:用copy修饰的 或者[XXX copy]的 变量肯定是不可变的。即便是修饰NSMutableArray或者NSMutableDictionary 所以通常用Strong来修饰NSMutableArray NSMutableDictionary 否则适用可能会闪退
2:用copy修饰或者[xxx copy],要看源对象是否是可变的,来决定只拷贝指针,还是也拷贝对象到另一块内存空间 即如果是NSArray、NSDictionary拷贝指针 NSMutableArray NSMutableDictionary拷贝生成新对象
3:对象之间mutableCopy赋值,肯定会拷贝整个对象内存到另一块内存中
如果NSArray中有Person对象 mutableCopy只会对NSArray进行深拷贝 Array内部的Person、ViewController、NSMutableString等对象一律不变(可以节省内存空间?)即新Array的地址空间变了 但是里面的对象还是老对象
苹果官方称为:one-level-deep copy 集合的单层深拷贝
4:[[NSDictionary alloc] initWithDictionary:someDictionary copyItems:YES]
如果你用这种方法深拷贝,集合里的每个对象都会收到 copyWithZone: 消息。如果集合里的对象都遵循 NSCopying 协议,那么对象就会被深拷贝到新的集合。如果对象没有遵循 NSCopying 协议,而尝试用这种方法进行深拷贝,会在运行时出错。
5:[NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:oldArray]] 集合的归档解档可以完全生成新对象 归档解档貌似一样要序列化 😄
部分内容来自:https://www.jianshu.com/p/eb1b732b737d
runtime对应源码:
void objc_setProperty_nonatomic_copy(id self, SEL _cmd, id newValue, ptrdiff_t offset)
{
reallySetProperty(self, _cmd, newValue, offset, false, true, false);
}
static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)
{
if (offset == 0) {
object_setClass(self, newValue);
return;
}
id oldValue;
id *slot = (id*) ((char*)self + offset);
if (copy) {
/*
The returned object is implicitly retained by the sender, who is responsible for releasing it. The copy returned is immutable if the consideration “immutable vs. mutable” applies to the receiving object; otherwise the exact nature of the copy is determined by the class.
返回的对象由负责释放它的发送者隐式保留(隐式retain)。 如果将不可变用于接收,则返回的副本是不可变的。 否则,副本的确切性质由类别决定。
1:没实现copyWithZone相关的copy协议会崩溃
2:会隐式retain 修饰不可变时和retain或者strong区别不大
/
newValue = [newValue copyWithZone:nil];
} else if (mutableCopy) {
newValue = [newValue mutableCopyWithZone:nil];
} else {
if (slot == newValue) return;
newValue = objc_retain(newValue);
}
if (!atomic) {
oldValue = *slot;
*slot = newValue;
} else {
//atomic线程安全的自旋锁
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
oldValue = *slot;
*slot = newValue;
slotlock.unlock();
}
objc_release(oldValue);
}
自定义类的copy
- (id)copyWithZone:(NSZone *)zone {
Person *p = [[self class] allocWithZone:zone];
p.name = self.name;
return p;
} - (id)mutableCopyWithZone:(NSZone *)zone {
Person *p = [[self class] allocWithZone:zone];
p.name = self.name;
return p;
}
allocWithZone方法介绍说,该方法的参数是被忽略的,正确的做法是传nil或者NULL参数给它。而这个方法之所以存在,是历史遗留原因;所以这个zone一直是nil 系统会分配新的内存空间 所以自定义类全是深拷贝?
- (instancetype)sharePseron {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_p = [[self alloc] init];;
});
return _p;
} - (instancetype)allocWithZone:(NSZone *)zone {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_p = [super allocWithZone:zone];
});
return _p;
}
- (id)copyWithZone:(NSZone *)zone
{
return _p;
}