一文明白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下,我們不常使用這個修飾符。

對於不喜歡看純文字的童鞋,來來來,上圖:


對於也不喜歡看圖的童鞋,來來來,上代碼:

//
//  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,在MRC時代,引入了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)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章