美文网首页iOS 开发每天分享优质文章iOS面试iOS学习笔记
关于copy属性的正确用法,copy和strong的区别

关于copy属性的正确用法,copy和strong的区别

作者: jlstmac | 来源:发表于2019-10-21 16:00 被阅读0次

做过iOS开发的同学肯定都用过copy属性,但是copy属性和strong的区别可能还有很多人并不是很清楚,这一篇文章就专门讲一讲copy这个属性。

首先抛出本篇文章的结论:
可以简单的把copy属性理解为把目标参数copy,也就是拷贝之后再赋值给成员变量。

以下是生成set方法的源码,可以参考。

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) {
    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 {
    spinlock_t& slotlock = PropertyLocks[slot];
    slotlock.lock();
    oldValue = *slot;
    *slot = newValue;        
    slotlock.unlock();
}

objc_release(oldValue);

}

从这里可以看出来copy和strong的区别主要在于copy这个动作。
那么copy的作用到底是什么?这个动作对于不同Object又有什么不同作用呢?copy和mutableCopy又有什么区别呢?
这里再一次抛出结论:
对不可变变量(例如NSString)进行不可变拷贝(copy),是浅拷贝(引用计数+1),其他情况都是深拷贝。
对不可变变量(例如NSString)来说定义成copy,更加安全,但是效率也更低

为什么更加安全?
我们把一个变量定义成NSString,那一定是我们不希望它的值被任意改变。如果定义属性的时候使用strong,那就有可能存在被任意,或者意料之外改动的情况。
我们来看一个例子:

@interface ViewController ()
@property (nonatomic, strong) NSString* strongString;
@property (nonatomic, copy) NSString* copyedString;
@end

- (void)copyTest
{
    NSMutableString* mstr = [NSMutableString stringWithFormat:@"I'am mutableString"];
    self.strongString = mstr;
    self.copyedString = mstr;
    [self printAdress:mstr];
    
    [mstr insertString:@"and I'am copyed" atIndex:mstr.length];
    
    [self printString:mstr];
}

- (void)printAdress:(NSString*)str
{
    NSLog(@"*****************");
    NSLog(@"str:%p",str);
    NSLog(@"storng:%p",(_strongString));
    NSLog(@"copy:%p",(_copyedString));
}

- (void)printString:(NSString*)str
{
    NSLog(@"+++++++++++++");
    NSLog(@"str:%@",str);
    NSLog(@"storng:%@",(_strongString));
    NSLog(@"copy:%@",(_copyedString));
}

输出结果:

*****************
str:0x60000058fe10
storng:0x60000058fe10
copy:0x60000058fae0
+++++++++++++
str:I'am mutableStringand I'am copyed
storng:I'am mutableStringand I'am copyed
copy:I'am mutableString

由于strongString是定义成了strong,在被赋予一个NSMutableString的变量mstr之后,对mstr进行修改,strongString也被修改了。这相当于对一个不可变变量间接进行了修改。
为什么更低效?
原因很简单,因为需要深拷贝,需要重新开辟空间并且赋值。
但是,不是把属性定义成copy就万事大吉了,需要注意的是在类内部还是需要使用self.copyedString的方式或者[self setCopyedString]调用,如果直接_copyedString=mstring的方式还是不会起到效果,因为没有调用setter方法

Block属性最好使用copy

虽然对于Block来说,ARC环境下使用copy和strong的效果一样(因为即使是定义成strong,赋值的时候依然会为我们拷贝),但是我们最好使用copy修饰。
原因跟Block的内存分布有关系。
Block根据他们在内存的位置分为三种:
1.NSStackBlock(在栈区,超出作用域就会自动释放)。
2.NSMallocBlock(在堆区,生命周期由程序员手动管理)。
3.NSGlobalBlock(全局区)。
对于栈区的Block可以进行一次拷贝,把栈区的Block拷贝到堆区。
在MRC下必须使用copy,以完成拷贝。沿用到ARC下最好也用copy,以表明其工作原理。
关于Block的内存分布是一个非常复杂的话题,这里就不展开了。

相关文章

网友评论

    本文标题:关于copy属性的正确用法,copy和strong的区别

    本文链接:https://www.haomeiwen.com/subject/hhzjyctx.html