一文明白strong,weak,assign, copy, retain,有源码

我们在项目中经常声明属性,属性的引用类型修饰符有strong,weak,assign, copy, retain,它们分别有何含义呢?我们来做一次总结。

由于iOS的内存管理机制是引用计数管理,也就是说当一个对象创建的时候,引用计数为1,当对这个对象进行copy操作的时候,引用计数会加1,当不需要使用这个对象的时候,系统会进行release操作,引用计数减1,当引用计数为0的时候,系统就会把这个对象释放掉。

  • strong:当使用strong修饰一个指针的时候,这个指针是一个强引用类型,当它指向一个对象的时候,这个对象的引用计数会加1 。
  • weak: 当使用weak修饰一个指针的时候,这个指针是一个弱引用类型,当它指向一个对象的时候,这个对象的引用计数并不会加1 。
  • assign: 对于值类型而言,声明的时候使用assign进行修饰。
  • copy: 对于不可变类型,copy修饰的指针是浅拷贝,指向的内存地址引用计数加1,当copy修饰的指针值改变的时候,地址也会改变,原来指向的地址的引用计数减1.对于可变类型而言,copy修饰的指针是深拷贝,把指向的对象的值拷贝一份。
  • retain: 是MRC遗留下来的修饰符,目前和strong一样,修饰的属性指向的地址引用计数加1 ,在ARC下,我们不常使用这个修饰符。

对于不喜欢看纯文字的童鞋,来来来,上图:


image.png
image.png

对于也不喜欢看图的童鞋,来来来,上代码:

//
//  ViewController.m
//  Test
//
//  Created by wenhuanhuan on 2020/6/17.
//  Copyright © 2020 weiman. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

@property(nonatomic, strong)NSString * sA;
@property(nonatomic, weak)NSString * wA;
@property(nonatomic, copy)NSString * cA;
@property(nonatomic, retain)NSString * rA;

@property(nonatomic, strong)NSArray * sArr;
@property(nonatomic, weak)NSArray * wArr;
@property(nonatomic, copy)NSArray * cArr;
@property(nonatomic, retain)NSArray * rArr;

@property(nonatomic, weak)NSSet * wSet;
@property(nonatomic, assign)NSSet * aSet;

@end

@implementation ViewController

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

-(void)test_a {
   @autoreleasepool {
       NSSet * set = [NSSet setWithObjects:@"1", @"2", @"3", nil];
       [self printWithObj:set mark:@"set"];//retainCount: 1
       self.wSet = set;
       [self printWithObj:set mark:@"set weak"];//retainCount: 1
       self.aSet = set;
       [self printWithObj:set mark:@"set assign"];//retainCount: 1
          
       set = [NSSet setWithObjects:@"6", @"8", @"5", nil];
       [self printWithObj:set mark:@"set change"];
   }
  
   NSLog(@"self.wSet = %p  %@", self.wSet, self.wSet);
//由于set已经释放了,self.aSet变成了野指针,访问野指针崩溃
  // NSLog(@"self.aSet = %p  %@", self.aSet, self.aSet);
}

-(void)test_p {
   
   NSLog(@"-------非集合,不可变类型---NSString------------\n");
   /**
   对于NSString类型,苹果做了优化,retainCount值为-1
   */
   NSString * sA1 = @"小莉莉";
   [self printWithObj:sA1 mark:@"NSString test1"];
   NSString * sA2 = [[NSString alloc]init];
   [self printWithObj:sA2 mark:@"NSString test2"];
   printf("\n\n");
   
   //使用如下方法创建的NSString对象,retainCount值为1
   NSString * str = [[NSString alloc] initWithUTF8String:"小红花"];
   [self printWithObj:str mark:@"NSString test3"];//retainCount = 1
   self.sA = str;
   [self printWithObj:str mark:@"NSString test4"];//retainCount = 2
   self.wA = str;
   [self printWithObj:str mark:@"NSString test5"];//retainCount = 2
   self.cA = str;
   [self printWithObj:str mark:@"NSString test6"];//retainCount = 3
   self.cA = @"copy";
   [self printWithObj:str mark:@"NSString test7"];//retainCount = 2
   self.rA = str;
   [self printWithObj:str mark:@"NSString test8"];//retainCount = 3
   
   
   printf("\n\n");
   NSLog(@"-------非集合,可变类型---NSMutableString------------\n");
   NSMutableString * mStr = [[NSMutableString alloc]initWithString:@"可变字符串"];
   [self printWithObj:mStr mark:@"NSMutableString test1"];//retainCount = 1
   self.sA = mStr;
   [self printWithObj:mStr mark:@"NSMutableString test2"];//retainCount = 2
   self.wA = mStr;
   [self printWithObj:mStr mark:@"NSMutableString test3"];//retainCount = 2
   self.cA = mStr;
   [self printWithObj:mStr mark:@"NSMutableString test4"];//retainCount = 2
   self.rA = mStr;
   [self printWithObj:mStr mark:@"NSMutableString test5"];//retainCount = 3
   [self printWithObj:self.sA mark:@"sA"];
   [self printWithObj:self.cA mark:@"cA"];
   
   printf("\n\n");
   NSLog(@"-------集合,不可变类型---NSArray------------\n");
   NSArray * arr = @[@1,@2];
   [self printWithObj:arr mark:@"NSArray test1"];//retainCount = 1
   self.sArr = arr;
   [self printWithObj:arr mark:@"NSArray test2"];//retainCount = 2
   self.wArr = arr;
   [self printWithObj:arr mark:@"NSArray test3"];//retainCount = 2
   self.cArr = arr;
   [self printWithObj:arr mark:@"NSArray test4"];//retainCount = 3
   self.cArr = @[@5, @6];
   [self printWithObj:arr mark:@"NSArray test4"];//retainCount = 2
   self.rArr = arr;
   [self printWithObj:arr mark:@"NSArray test5"];//retainCount = 3
   
   printf("\n\n");
   NSLog(@"-------集合,可变类型---NSMutableArray------------\n");
   NSMutableArray * mArr = [NSMutableArray arrayWithObjects:@"a",@"b", nil];
   [self printWithObj:mArr mark:@"NSMutableArray test1"];//retainCount = 1
   self.sArr = mArr;
   [self printWithObj:mArr mark:@"NSMutableArray test1"];//retainCount = 2
   self.wArr = mArr;
   [self printWithObj:mArr mark:@"NSMutableArray test1"];//retainCount = 2
   self.cArr = mArr;
   [self printWithObj:mArr mark:@"NSMutableArray test1"];//retainCount = 2
   self.cArr = @[@"iii"];
   [self printWithObj:mArr mark:@"NSMutableArray test1"];//retainCount = 2
   self.rArr = mArr;
   [self printWithObj:mArr mark:@"NSMutableArray test1"];//retainCount = 3
}

-(void)printWithObj: (id)obj mark: (NSString *)str {
   NSLog(@"%@ 值:%@, 地址: %p, retainCount: %ld", str, obj, obj, (unsigned long)[obj retainCount]);
}
@end

总结

在MRC时代,关于属性引用计数的修饰符是retain, copy, assign,在ARC时代,引入了strong和weak。
strong:强引用,引用计数增加;
weak:弱引用,引用计数不增加;
assign:修饰值类型,修饰对象的时候,类似于weak,引用计数不增加。但是当对象释放的时候,assign指针不会释放,造成野指针,再次访问,会崩溃,而weak则不会崩溃。
retain:MRC下遗留的修饰符,引用计数会增加,类似于strong,ARC下,我们不常使用。
copy:对于不可变类型,copy修饰的指针是浅拷贝,指向的内存地址引用计数加1,当copy修饰的指针值改变的时候,地址也会改变,原来指向的地址的引用计数减1。对于可变类型而言,copy修饰的指针是深拷贝,把指向的对象的值拷贝一份。

打印结果:

2020-06-21 17:19:34.926294+0800 Test[2573:170127] -------非集合,不可变类型---NSString------------

2020-06-21 17:19:34.926497+0800 Test[2573:170127] NSString test1 值:小莉莉, 地址: 0x107ee01d8, retainCount: -1
2020-06-21 17:19:34.926634+0800 Test[2573:170127] NSString test2 值:, 地址: 0x7fff80971d08, retainCount: -1


2020-06-21 17:19:34.926823+0800 Test[2573:170127] NSString test3 值:小红花, 地址: 0x60000332af20, retainCount: 1
2020-06-21 17:19:34.926944+0800 Test[2573:170127] NSString test4 值:小红花, 地址: 0x60000332af20, retainCount: 2
2020-06-21 17:19:34.927091+0800 Test[2573:170127] NSString test5 值:小红花, 地址: 0x60000332af20, retainCount: 2
2020-06-21 17:19:34.927214+0800 Test[2573:170127] NSString test6 值:小红花, 地址: 0x60000332af20, retainCount: 3
2020-06-21 17:19:34.927340+0800 Test[2573:170127] NSString test7 值:小红花, 地址: 0x60000332af20, retainCount: 2
2020-06-21 17:19:34.927552+0800 Test[2573:170127] NSString test8 值:小红花, 地址: 0x60000332af20, retainCount: 3


2020-06-21 17:19:34.927868+0800 Test[2573:170127] -------非集合,可变类型---NSMutableString------------

2020-06-21 17:19:34.928174+0800 Test[2573:170127] NSMutableString test1 值:可变字符串, 地址: 0x600003d37420, retainCount: 1
2020-06-21 17:19:34.928456+0800 Test[2573:170127] NSMutableString test2 值:可变字符串, 地址: 0x600003d37420, retainCount: 2
2020-06-21 17:19:34.928759+0800 Test[2573:170127] NSMutableString test3 值:可变字符串, 地址: 0x600003d37420, retainCount: 2
2020-06-21 17:19:34.929087+0800 Test[2573:170127] NSMutableString test4 值:可变字符串, 地址: 0x600003d37420, retainCount: 2
2020-06-21 17:19:34.935395+0800 Test[2573:170127] NSMutableString test5 值:可变字符串, 地址: 0x600003d37420, retainCount: 3
2020-06-21 17:19:34.935553+0800 Test[2573:170127] sA 值:可变字符串, 地址: 0x600003d37420, retainCount: 3
2020-06-21 17:19:34.935701+0800 Test[2573:170127] cA 值:可变字符串, 地址: 0x600003d33c60, retainCount: 1


2020-06-21 17:19:34.935822+0800 Test[2573:170127] -------集合,不可变类型---NSArray------------

2020-06-21 17:19:34.936007+0800 Test[2573:170127] NSArray test1 值:(
    1,
    2
), 地址: 0x6000033258e0, retainCount: 1
2020-06-21 17:19:34.936148+0800 Test[2573:170127] NSArray test2 值:(
    1,
    2
), 地址: 0x6000033258e0, retainCount: 2
2020-06-21 17:19:34.936287+0800 Test[2573:170127] NSArray test3 值:(
    1,
    2
), 地址: 0x6000033258e0, retainCount: 2
2020-06-21 17:19:34.936424+0800 Test[2573:170127] NSArray test4 值:(
    1,
    2
), 地址: 0x6000033258e0, retainCount: 3
2020-06-21 17:19:34.936564+0800 Test[2573:170127] NSArray test4 值:(
    1,
    2
), 地址: 0x6000033258e0, retainCount: 2
2020-06-21 17:19:34.936717+0800 Test[2573:170127] NSArray test5 值:(
    1,
    2
), 地址: 0x6000033258e0, retainCount: 3


2020-06-21 17:19:34.936843+0800 Test[2573:170127] -------集合,可变类型---NSMutableArray------------

2020-06-21 17:19:34.936990+0800 Test[2573:170127] NSMutableArray test1 值:(
    a,
    b
), 地址: 0x600003d37690, retainCount: 1
2020-06-21 17:19:34.937306+0800 Test[2573:170127] NSMutableArray test1 值:(
    a,
    b
), 地址: 0x600003d37690, retainCount: 2
2020-06-21 17:19:34.937627+0800 Test[2573:170127] NSMutableArray test1 值:(
    a,
    b
), 地址: 0x600003d37690, retainCount: 2
2020-06-21 17:19:34.937942+0800 Test[2573:170127] NSMutableArray test1 值:(
    a,
    b
), 地址: 0x600003d37690, retainCount: 2
2020-06-21 17:19:34.938245+0800 Test[2573:170127] NSMutableArray test1 值:(
    a,
    b
), 地址: 0x600003d37690, retainCount: 2
2020-06-21 17:19:34.938527+0800 Test[2573:170127] NSMutableArray test1 值:(
    a,
    b
), 地址: 0x600003d37690, retainCount: 3
2020-06-21 17:19:34.938856+0800 Test[2573:170127] set 值:{(
    1,
    2,
    3
)}, 地址: 0x600003d38840, retainCount: 1
2020-06-21 17:19:34.939117+0800 Test[2573:170127] set weak 值:{(
    1,
    2,
    3
)}, 地址: 0x600003d38840, retainCount: 1
2020-06-21 17:19:34.939376+0800 Test[2573:170127] set assign 值:{(
    1,
    2,
    3
)}, 地址: 0x600003d38840, retainCount: 1
2020-06-21 17:19:34.939715+0800 Test[2573:170127] set change 值:{(
    6,
    8,
    5
)}, 地址: 0x600003d376f0, retainCount: 1
2020-06-21 17:19:34.939985+0800 Test[2573:170127] self.wSet = 0x0  (null)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 226,913评论 6 527
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 97,710评论 3 412
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 174,561评论 0 373
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 62,278评论 1 306
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 71,080评论 6 405
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 54,604评论 1 320
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 42,698评论 3 434
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 41,847评论 0 285
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 48,361评论 1 329
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 40,330评论 3 353
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 42,487评论 1 365
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 38,044评论 5 355
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 43,738评论 3 342
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 34,134评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 35,378评论 1 281
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 51,053评论 3 385
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 47,471评论 2 370