浅谈strong.copy

当谈及深拷贝、浅拷贝的时候,大家第一个想到的就是strong、copy。很多人会进入一个误区:认为strong就是浅拷贝,copy就是深拷贝。

我们先上代码,猜猜看打印的结果:

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic, strong) NSString   *sStr;
@property (nonatomic, copy) NSString   *cStr;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSString *str = @"aaa";
    self.sStr = str;
    self.cStr = str;
    str = @"bbb";

    NSLog(@"\nself.sStr:%p\nself.cStr:%p\nstr:%p",self.sStr,self.cStr,str);
    NSLog(@"\nself.sStr:%@\nself.cStr:%@\nstr:%@",self.sStr,self.cStr,str);
    NSLog(@"\nself.sStr:%p\nself.cStr:%p\nstr:%p",&_sStr,&_cStr,&str);
}

结果为:

2017-12-25 16:31:49.907114+0800 StrongCopy[3187:564413] 
self.sStr:0x10e3e0078
self.cStr:0x10e3e0078
str:0x10e3e0098
2017-12-25 16:31:49.907364+0800 StrongCopy[3187:564413] 
self.sStr:aaa
self.cStr:aaa
str:bbb
2017-12-25 16:31:49.907619+0800 StrongCopy[3187:564413] 
self.sStr:0x7f9f3c701260
self.cStr:0x7f9f3c701268
str:0x7ffee181eb98

看到这个结果,很多人会疑惑为什么self.cStr会是aaa

解释:

str = @"bbb";

这句代码指针指向发生了变化,str指向了新的内存,而strong、copy还是指向原来的的内存。有一点不要迷惑,就是打印的第三句获取地址,是指获取指针的地址,三个内容在三个不同的地方,所以不一样。


我们再看另外一段代码:

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic, strong) NSString   *sStr;
@property (nonatomic, copy) NSString   *cStr;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSMutableString *mutableStr = [NSMutableString stringWithFormat:@"ccc"];
    self.sStr = mutableStr;
    self.cStr = mutableStr;
    [mutableStr appendFormat:@"ddd"];
    NSLog(@"\nself.sStr:%p\nself.cStr:%p\nstr:%p",self.sStr,self.cStr,mutableStr);
    NSLog(@"\nself.sStr:%@\nself.cStr:%@\nstr:%@",self.sStr,self.cStr,mutableStr);
    NSLog(@"\nself.sStr:%p\nself.cStr:%p\nstr:%p",&_sStr,&_cStr,&mutableStr);
}

结果为:

2017-12-25 16:39:29.395377+0800 StrongCopy[3205:592287] 
self.sStr:0x604000451160
self.cStr:0xa000000006363633
str:0x604000451160
2017-12-25 16:39:29.395643+0800 StrongCopy[3205:592287] 
self.sStr:cccddd
self.cStr:ccc
str:cccddd
2017-12-25 16:39:29.395967+0800 StrongCopy[3205:592287] 
self.sStr:0x7f94ea40e1d0
self.cStr:0x7f94ea40e1d8
str:0x7ffee4a04b98

这下是不是跟自己想的一样了呢?

解释:
生成可变字符串,然后再拼接字符串,拼接的内容是在原来内存上拼接的,所以地址没变。self.sStr和mutableStr指向的是同一块内存地址,所以self.sStr跟着变。但是self.cStr生成的是一个新的地址,也就是深拷贝(内容和指针都拷贝)。mutableStr改变不影响self.cStr。

总结有张图:


简单总结:

strong:实际是retain持有对象

copy:浅拷贝的时候等同于strong,深拷贝是拷贝了对象和指针。

对象拷贝(strong):

#import <Foundation/Foundation.h>

@interface Person : NSObject<NSCopying>

@property (nonatomic, strong) NSString   *sStr;
@property (nonatomic, copy) NSString   *cStr;

@end


#import "Person.h"

@implementation Person

- (id)copyWithZone:(nullable NSZone *)zone{
    Person *p = [[Person allocWithZone:zone] init];
    p.sStr = self.sStr;
    p.cStr = self.cStr;
    return p;
}

@end


#import "ViewController.h"
#import "Person.h"

@interface ViewController ()

@property (nonatomic, strong) Person   *person;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    Person *p = [[Person alloc] init];
    p.sStr = @"aaa";
    p.cStr = @"bbb";
    self.person = p;
    NSLog(@"\np.sStr--%p,\nself.person.sStr--%p,\np.cStr--%p,\nself.person.cStr--%p",p.sStr,self.person.sStr,p.cStr,self.person.cStr);
    NSLog(@"\np.sStr--%@,\nself.person.sStr--%@,\np.cStr--%@,\nself.person.cStr--%@",p.sStr,self.person.sStr,p.cStr,self.person.cStr);
    
    p.sStr = @"ccc";
    p.cStr = @"ddd";
    NSLog(@"\np.sStr--%p,\nself.person.sStr--%p,\np.cStr--%p,\nself.person.cStr--%p",p.sStr,self.person.sStr,p.cStr,self.person.cStr);
    NSLog(@"\np.sStr--%@,\nself.person.sStr--%@,\np.cStr--%@,\nself.person.cStr--%@",p.sStr,self.person.sStr,p.cStr,self.person.cStr);
}

打印结果:

2017-12-25 17:20:53.798643+0800 StrongCopy[3280:684726] 
p.sStr--0x10a172078,
self.person.sStr--0x10a172078,
p.cStr--0x10a172098,
self.person.cStr--0x10a172098
2017-12-25 17:20:53.798881+0800 StrongCopy[3280:684726] 
p.sStr--aaa,
self.person.sStr--aaa,
p.cStr--bbb,
self.person.cStr--bbb
2017-12-25 17:20:53.799022+0800 StrongCopy[3280:684726] 
p.sStr--0x10a1720f8,
self.person.sStr--0x10a1720f8,
p.cStr--0x10a172118,
self.person.cStr--0x10a172118
2017-12-25 17:20:53.799155+0800 StrongCopy[3280:684726] 
p.sStr--ccc,
self.person.sStr--ccc,
p.cStr--ddd,
self.person.cStr--ddd

对象拷贝(copy):


#import "ViewController.h"
#import "Person.h"

@interface ViewController ()

@property (nonatomic, copy) Person   *person;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    Person *p = [[Person alloc] init];
    p.sStr = @"aaa";
    p.cStr = @"bbb";
    self.person = p;
    NSLog(@"\np.sStr--%p,\nself.person.sStr--%p,\np.cStr--%p,\nself.person.cStr--%p",p.sStr,self.person.sStr,p.cStr,self.person.cStr);
    NSLog(@"\np.sStr--%@,\nself.person.sStr--%@,\np.cStr--%@,\nself.person.cStr--%@",p.sStr,self.person.sStr,p.cStr,self.person.cStr);
    
    p.sStr = @"ccc";
    p.cStr = @"ddd";
    NSLog(@"\np.sStr--%p,\nself.person.sStr--%p,\np.cStr--%p,\nself.person.cStr--%p",p.sStr,self.person.sStr,p.cStr,self.person.cStr);
    NSLog(@"\np.sStr--%@,\nself.person.sStr--%@,\np.cStr--%@,\nself.person.cStr--%@",p.sStr,self.person.sStr,p.cStr,self.person.cStr);
}

结果:

2017-12-25 17:28:24.113611+0800 StrongCopy[3310:712017] 
p.sStr--0x10962d078,
self.person.sStr--0x10962d078,
p.cStr--0x10962d098,
self.person.cStr--0x10962d098
2017-12-25 17:28:24.113876+0800 StrongCopy[3310:712017] 
p.sStr--aaa,
self.person.sStr--aaa,
p.cStr--bbb,
self.person.cStr--bbb
2017-12-25 17:28:24.114010+0800 StrongCopy[3310:712017] 
p.sStr--0x10962d0f8,
self.person.sStr--0x10962d078,
p.cStr--0x10962d118,
self.person.cStr--0x10962d098
2017-12-25 17:28:24.114141+0800 StrongCopy[3310:712017] 
p.sStr--ccc,
self.person.sStr--aaa,
p.cStr--ddd,
self.person.cStr--bbb

property copy 实际上就对sStr干了这个:

- (void)setSStr:(NSString *)sStr{
    _sStr = [sStr copy];
}

代码地址:https://github.com/CoderJon/DeepShallowCopy





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值