OC学习27:Copy和Strong探索

张建 lol

简介

  • 在属性 @property 中存在 copy、strong 修饰符,不存在 mutableCopy

  • 对于可变对象属性 (NSMutableString、NSMutableDictionary、NSMutableArray) 与 不可变对象属性 (NSString、NSDictionary、NSArray)而言,修饰不可变的对象属性用copy,修饰可变的对象属性用strong

NSString字符串

  • __NSCFConstantString 是常量字符串,存储在数据区。
  • __NSCFString 表示为oc对象,NSString就是封装的CFString,这个字符串对象存储在堆中。
  • NSTaggedPointerString 这个类表示这是字符串的一种指针Tagged Pointer
  1. 不可变的字符串NSString,用NSString赋值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@interface ViewController ()
@property (nonatomic,copy)NSString * strCopy;
@property (nonatomic,strong)NSString * strStrong;
@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];
[self demo];
}

- (void)demo{

NSString * str = @"123";
self.strCopy = str;
self.strStrong = str;
// 改变之前
NSLog(@"str:%@-%p", str, str);
NSLog(@"strCopy:%@-%p-%@", self.strCopy, self.strCopy,[self.strCopy class]);
NSLog(@"strStrong:%@-%p-%@", self.strStrong, self.strStrong,[self.strStrong class]);
// 改变之后
str = @"234";
NSLog(@"str:%@-%p", str, str);
NSLog(@"strCopy:%@-%p-%@", self.strCopy, self.strCopy,[self.strCopy class]);
NSLog(@"strStrong:%@-%p-%@", self.strStrong, self.strStrong,[self.strStrong class]);
}

查看打印结果

1
2
3
4
5
6
7
2020-08-25 20:40:52.062970+0800 OC-copy和strong[44465:2260522] str:123-0x101b1c028
2020-08-25 20:40:52.063214+0800 OC-copy和strong[44465:2260522] strCopy:123-0x101b1c028-__NSCFConstantString
2020-08-25 20:40:52.063389+0800 OC-copy和strong[44465:2260522] strStrong:123-0x101b1c028-__NSCFConstantString

2020-08-25 20:40:52.063510+0800 OC-copy和strong[44465:2260522] str:234-0x101b1c0a8
2020-08-25 20:40:52.063629+0800 OC-copy和strong[44465:2260522] strCopy:123-0x101b1c028-__NSCFConstantString
2020-08-25 20:40:52.063743+0800 OC-copy和strong[44465:2260522] strStrong:123-0x101b1c028-__NSCFConstantString

我们发现:

  • str在改变之前用copy和strong修饰的值和内存地址均没有改变,返回不可变对象__NSCFConstantString

  • str改变之后str指向了新的内存地址,从而值改变了,不影响copy和strong修饰的字符串,返回不可变对象__NSCFConstantString

结论:
使用 NSString 赋值给 NSString 的时候,无论使用 copy 还是 strong 都是 深拷贝

  1. 不可变的字符串NSString,用NSMutableString赋值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- (void)demo1{
NSMutableString * mstr = [NSMutableString stringWithFormat:@"123"];
self.strCopy = mstr;
self.strStrong = mstr;

// 改变之前
NSLog(@"str:%@-%p", str, str);
NSLog(@"strCopy:%@-%p-%@", self.strCopy, self.strCopy,[self.strCopy class]);
NSLog(@"strStrong:%@-%p-%@", self.strStrong, self.strStrong,[self.strStrong class]);

// 改变之后
str = @"234";
NSLog(@"str:%@-%p", str, str);
NSLog(@"strCopy:%@-%p-%@", self.strCopy, self.strCopy,[self.strCopy class]);
NSLog(@"strStrong:%@-%p-%@", self.strStrong, self.strStrong,[self.strStrong class]);
}

打印结果

1
2
3
4
5
6
7
8
2020-08-25 20:51:56.553156+0800 OC-copy和strong[44569:2268592] str:123-0x60000192f9c0-__NSCFString
2020-08-25 20:51:56.553390+0800 OC-copy和strong[44569:2268592] strCopy:123-0xb174ce39c84cf2fe-NSTaggedPointerString
2020-08-25 20:51:56.553533+0800 OC-copy和strong[44569:2268592] strStrong:123-0x60000192f9c0-__NSCFString

2020-08-25 20:51:56.553636+0800 OC-copy和strong[44569:2268592] str:123456-0x60000192f9c0-__NSCFString
2020-08-25 20:51:56.555326+0800 OC-copy和strong[44569:2268592] strCopy:123-0xb174ce39c84cf2fe-NSTaggedPointerString
2020-08-25 20:51:56.555514+0800 OC-copy和strong[44569:2268592] strStrong:123456-0x60000192f9c0-__NSCFString

我们发现:

  • MutableString 赋值给 NSString 时,copy 拷贝了新的对象,指向新的内存空间,深拷贝,返回NSTaggedPointerString;
  • strong指向同一个内存空间,浅拷贝,返回 __NSCFString

结论:使用MutableString赋值时,copy是深拷贝,strong是浅拷贝

NSMutableString字符串

  1. 不能使用NSString直接赋值给NSMutableString,会报警告
1
Incompatible pointer types assigning to 'NSMutableString *' from 'NSString *'
  1. 使用NSMutableString赋值给NSMutableString
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- (void)demo2{
NSMutableString * mstr = [NSMutableString stringWithFormat:@"123"];
self.strMCopy = mstr;
self.strMStrong = mstr;

// 改变之前
NSLog(@"mstr:%@-%p-%@", mstr, mstr,[mstr class]);
NSLog(@"strMCopy:%@-%p-%@", self.strMCopy, self.strMCopy,[self.strMCopy class]);
NSLog(@"strMStrong:%@-%p-%@", self.strMStrong, self.strMStrong,[self.strMStrong class]);

// 改变之后
[mstr appendFormat:@"456"];
// [self.strMCopy appendFormat:@"7"]; //报错,因为
// [self.strMStrong appendFormat:@"8"]; // 可以正常使用
NSLog(@"mstr:%@-%p-%@", mstr, mstr,[mstr class]);
NSLog(@"strMCopy:%@-%p-%@", self.strMCopy, self.strMCopy,[self.strMCopy class]);
NSLog(@"strMStrong:%@-%p-%@", self.strMStrong, self.strMStrong,[self.strMStrong class]);
}

查看结果

1
2
3
4
5
6
7
8
2020-08-25 20:59:31.642078+0800 OC-copy和strong[44603:2273858] mstr:123-0x600001c8bb10-__NSCFString
2020-08-25 20:59:31.642335+0800 OC-copy和strong[44603:2273858] strMCopy:123-0xd5ae0af186ac50bb-NSTaggedPointerString
2020-08-25 20:59:31.642466+0800 OC-copy和strong[44603:2273858] strMStrong:123-0x600001c8bb10-__NSCFString

2020-08-25 20:59:31.642608+0800 OC-copy和strong[44603:2273858] mstr:123456-0x600001c8bb10-__NSCFString
2020-08-25 20:59:31.642731+0800 OC-copy和strong[44603:2273858] strMCopy:123-0xd5ae0af186ac50bb-NSTaggedPointerString
2020-08-25 20:59:31.642963+0800 OC-copy和strong[44603:2273858] strMStrong:123456-0x600001c8bb10-__NSCFString

由结果可知:
copy拷贝了一个新的对象,指向新的内存地址,深拷贝,返回NSTaggedPointerString;
strong指向同一个内存地址,引用计数+1,返回__NSCFString

数组

  1. 用NSArray赋值NSArray
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#import "ViewController.h"

@interface ViewController ()
@property (nonatomic,copy)NSArray * arrCopy;
@property (nonatomic,strong)NSArray * arrStrong;
@end
- (void)demo3{
NSArray * arr = @[@"1",@"2",@"3"];
self.arrCopy = arr;
self.arrStrong = arr;
NSLog(@"arr:%@-%p", arr, arr);
NSLog(@"arrCopy:%@-%p-%@", self.arrCopy, self.arrCopy,[self.arrCopy class]);
NSLog(@"arrStrong:%@-%p-%@", self.arrStrong, self.arrStrong,[self.arrStrong class]);

arr = @[@"2",@"3",@"4"];
self.arrCopy = arr;
self.arrStrong = arr;
NSLog(@"arr:%@-%p", arr, arr);
NSLog(@"arrCopy:%@-%p-%@", self.arrCopy, self.arrCopy,[self.arrCopy class]);
NSLog(@"arrStrong:%@-%p-%@", self.arrStrong, self.arrStrong,[self.arrStrong class]);
}

打印结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2020-08-25 19:25:42.826769+0800 OC-copy和strong[44074:2223987] arr:(
1,
2,
3
)-0x6000037518f0
2020-08-25 19:25:42.827010+0800 OC-copy和strong[44074:2223987] arrCopy:(
1,
2,
3
)-0x6000037518f0-__NSArrayI
2020-08-25 19:25:42.827146+0800 OC-copy和strong[44074:2223987] arrStrong:(
1,
2,
3
)-0x6000037518f0-__NSArrayI
2020-08-25 19:25:42.827452+0800 OC-copy和strong[44074:2223987] arr:(
2,
3,
4
)-0x6000037546c0
2020-08-25 19:25:42.827617+0800 OC-copy和strong[44074:2223987] arrCopy:(
2,
3,
4
)-0x6000037546c0-__NSArrayI
2020-08-25 19:25:42.827748+0800 OC-copy和strong[44074:2223987] arrStrong:(
2,
3,
4
)-0x6000037546c0-__NSArrayI

结论:
对于不可变的NSSArray用copy和strong修饰都会指向同一个内存地址,说明是浅拷贝,返回不可变数组。当addObject时,销毁之前的内存地址,重新开辟了一个内存地址

  1. 用NSMutableArray赋值NSArray
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (void)demo4{
NSMutableArray * marr = [NSMutableArray arrayWithArray:@[@"1",@"2",@"3"]];
self.arrCopy = marr;
self.arrStrong = marr;
NSLog(@"arr:%@-%p", marr, marr);
NSLog(@"arrCopy:%@-%p-%@", self.arrCopy, self.arrCopy,[self.arrCopy class]);
NSLog(@"arrStrong:%@-%p-%@", self.arrStrong, self.arrStrong,[self.arrStrong class]);

[marr addObject:@"4"];
self.arrCopy = marr;
self.arrStrong = marr;
NSLog(@"arr:%@-%p", marr, marr);
NSLog(@"arrCopy:%@-%p-%@", self.arrCopy, self.arrCopy,[self.arrCopy class]);
NSLog(@"arrStrong:%@-%p-%@", self.arrStrong, self.arrStrong,[self.arrStrong class]);
}

查看结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2020-08-25 19:34:32.073188+0800 OC-copy和strong[44141:2230084] arr:(
1,
2,
3
)-0x6000026ea850
2020-08-25 19:34:32.073428+0800 OC-copy和strong[44141:2230084] arrCopy:(
1,
2,
3
)-0x6000026eaac0-__NSArrayI
2020-08-25 19:34:32.073589+0800 OC-copy和strong[44141:2230084] arrStrong:(
1,
2,
3
)-0x6000026ea850-__NSArrayM
2020-08-25 19:34:32.073735+0800 OC-copy和strong[44141:2230084] arr:(
1,
2,
3,
4
)-0x6000026ea850
2020-08-25 19:34:32.073950+0800 OC-copy和strong[44141:2230084] arrCopy:(
1,
2,
3,
4
)-0x6000026daca0-__NSArrayI
2020-08-25 19:34:32.074085+0800 OC-copy和strong[44141:2230084] arrStrong:(
1,
2,
3,
4
)-0x6000026ea850-__NSArrayM

结论:
copy拷贝了一份新的数组,指向新的内存空间,深拷贝,返回不可变的数组,因此不能作为可变的去添加/删除元素。
strong指向同一个内存地址,引用计数+1,返回的是可变的数组。

  1. 不能用NSArray赋值NSMutableArray

  2. 用NSMutableArray赋值NSMutableArray

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (void)demo5{
NSMutableArray * marr = [NSMutableArray arrayWithArray:@[@"1",@"2",@"3"]];
self.arrmCopy = marr;
self.arrmStrong = marr;
NSLog(@"marr:%@-%p", marr, marr);
NSLog(@"arrmCopy:%@-%p-%@", self.arrmCopy, self.arrmCopy,[self.arrmCopy class]);
NSLog(@"arrmStrong:%@-%p-%@", self.arrmStrong, self.arrmStrong,[self.arrmStrong class]);

[marr addObject:@"4"];
self.arrmCopy = marr;
self.arrmStrong = marr;
NSLog(@"marr:%@-%p", marr, marr);
NSLog(@"arrmCopy:%@-%p-%@", self.arrmCopy, self.arrmCopy,[self.arrmCopy class]);
NSLog(@"arrmStrong:%@-%p-%@", self.arrmStrong, self.arrmStrong,[self.arrmStrong class]);
}

查看打印结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2020-08-25 19:45:18.878300+0800 OC-copy和strong[44201:2236266] marr:(
1,
2,
3
)-0x600003f19020
2020-08-25 19:45:18.878571+0800 OC-copy和strong[44201:2236266] arrmCopy:(
1,
2,
3
)-0x600003f191d0-__NSArrayI
2020-08-25 19:45:18.878729+0800 OC-copy和strong[44201:2236266] arrmStrong:(
1,
2,
3
)-0x600003f19020-__NSArrayM
2020-08-25 19:45:18.878872+0800 OC-copy和strong[44201:2236266] marr:(
1,
2,
3,
4
)-0x600003f19020
2020-08-25 19:45:18.879020+0800 OC-copy和strong[44201:2236266] arrmCopy:(
1,
2,
3,
4
)-0x600003f1d410-__NSArrayI
2020-08-25 19:45:18.879145+0800 OC-copy和strong[44201:2236266] arrmStrong:(
1,
2,
3,
4
)-0x600003f19020-__NSArrayM

结论:
copy相当于深拷贝,返回不可变的数组
strong相当于浅拷贝,返回可变的数组

字典和数组相同

总结:

  1. 当原数据是不可变数据时,不管使用strong还是copy修饰,都是指向原来的对象,copy操作只是做了一次浅拷贝。
  2. 当源数据是可变数据时,strong只是将源数据的引用计数加1,而copy则是对原字符串做了次深拷贝,从而生成了一个新的对象,并且copy的对象指向这个新对象。
  • Post title:OC学习27:Copy和Strong探索
  • Post author:张建
  • Create time:2020-08-25 12:22:47
  • Post link:https://redefine.ohevan.com/2020/08/25/OC/OC学习27:Copy和Strong探索/
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.