文明轉轉和評論是對自己的尊重也是對學者的鼓勵,謝謝
iOS-內存管理就這麼簡單2
一.copy,mutableCopy的使用
NSArray *arr = [[NSArray alloc]initWithObjects:@"hello", nil];
NSArray *arr2 = [arr copy];
NSObject *obj = [[NSObject alloc]init];
NSLog(@"arr retainCout %ld",[arr retainCount]);
NSLog(@"arr2 retainCout %ld",[arr2 retainCount]);
NSLog(@"arr = %ld arr2 =%ld ",arr,arr2);
2015-01-17 23:26:04.977 MemoryManager[907:40309] arr retainCout 2
2015-01-17 23:26:04.977 MemoryManager[907:40309] arr2 retainCout 2
2015-01-17 23:26:04.977 MemoryManager[907:40309] arr = 140677793151936 arr2 =140677793151936
說明通過copy得到的是同一個對象,copy使堆內存對象的引用計數加一了。NSArray *arr = [[NSArray alloc]initWithObjects:@"hello", nil];
NSArray *arr2 = [arr mutableCopy];
NSObject *obj = [[NSObject alloc]init];
NSLog(@"arr retainCout %ld",[arr retainCount]);
NSLog(@"arr2 retainCout %ld",[arr2 retainCount]);
NSLog(@"arr = %ld arr2 =%ld ",arr,arr2);
2015-01-17 23:28:12.817 MemoryManager[927:41217] arr retainCout 1
2015-01-17 23:28:12.817 MemoryManager[927:41217] arr2 retainCout 1
2015-01-17 23:28:12.817 MemoryManager[927:41217] arr = 140285358613872 arr2 =140285358605248
說明mutableCopy使把arr中的內容完全的賦值一份並存在新分配的堆內存對象中,所以arr和arr2指向的是不同的內存對象;NSArray *arr = [[NSArray alloc]initWithObjects:@"hello", nil];
NSArray *arr2 = [arr mutableCopy];
if([arr2 respondsToSelector:@selector(addObject:)]){
NSLog(@"changed");
}
NSObject *obj = [[NSObject alloc]init];
NSLog(@"arr retainCout %ld",[arr retainCount]);
NSLog(@"arr2 retainCout %ld",[arr2 retainCount]);
NSLog(@"arr = %ld arr2 =%ld ",arr,arr2);
運行結果:
2015-01-17 23:32:03.639 MemoryManager[950:42492] changed
2015-01-17 23:32:03.640 MemoryManager[950:42492] arr retainCout 1
2015-01-17 23:32:03.640 MemoryManager[950:42492] arr2 retainCout 1
2015-01-17 23:32:03.640 MemoryManager[950:42492] arr = 140367229411264 arr2 =140367229427648
NSMutableArray * arr2 = [[NSMutableArrayalloc]initWithArray:arr];
3.
NSMutableArray *arr = [[NSMutableArray alloc]initWithObjects:@"hello", nil];
NSMutableArray *arr2 = [arr mutableCopy];
if([arr2 respondsToSelector:@selector(addObject:)]){
NSLog(@"changed");
}
NSObject *obj = [[NSObject alloc]init];
NSLog(@"arr retainCout %ld",[arr retainCount]);
NSLog(@"arr2 retainCout %ld",[arr2 retainCount]);
NSLog(@"arr = %ld arr2 =%ld ",arr,arr2);
運行結果:
2015-01-17 23:38:24.378 MemoryManager[1034:44814] changed
2015-01-17 23:38:24.379 MemoryManager[1034:44814] arr retainCout 1
2015-01-17 23:38:24.379 MemoryManager[1034:44814] arr2 retainCout 1
2015-01-17 23:38:24.379 MemoryManager[1034:44814] arr = 140316907672672 arr2 =140316907807120
結果分析:可變數組mutableCopy還是可變數組,相當於NSMutableArray *arr2 = [[NSMutableArray alloc]initWithArray:arr];
arr和arr2還是指向不同堆中的對象,但它們的內容完全相同note:可變數組的mutableCopy之後還是可變的
5.
NSMutableArray *arr = [[NSMutableArray alloc]initWithObjects:@"hello", nil];
NSMutableArray *arr2 = [arr copy];
if([arr2 respondsToSelector:@selector(addObject:)]){
NSLog(@"changed");
}
NSObject *obj = [[NSObject alloc]init];
NSLog(@"arr retainCout %ld",[arr retainCount]);
NSLog(@"arr2 retainCout %ld",[arr2 retainCount]);
NSLog(@"arr = %ld arr2 =%ld ",arr,arr2);
2015-01-17 23:41:36.505 MemoryManager[1058:46071] arr retainCout 1
2015-01-17 23:41:36.506 MemoryManager[1058:46071] arr2 retainCout 1
2015-01-17 23:41:36.506 MemoryManager[1058:46071] arr = 140719784280096 arr2 =140719784275712
說明可變的數組通過copy函數相當於:NSArray *arr2 = [[NSArray alloc]initWithArray:arr];
不同堆對象相同內容,這就是所謂的深拷貝和淺拷貝,但要注意拷貝之後的對象的屬性性質的變化,其他的集合類和字符串也存在通過深拷貝和淺拷貝及對象性質的變化,所以在應用時要小心。note:可變的數組copy之後就成了不可變的。
二.循環引用和弱引用解決循環引用的內存泄漏
@interface CycleRetain : NSObject
@property (nonatomic,retain)id retainObject;
@end
@implementation CycleRetain
@end
CycleRetain *obj1 = [[CycleRetain alloc]init];//此時 obj1指向的堆對象的引用計數爲1
CycleRetain *obj2 = [[CycleRetain alloc]init];//此時 obj2指向的堆對象的引用計數爲1
NSLog(@"before ");
NSLog(@"obj1 retainCount=%ld obj2 retainCount=%ld",obj1.retainCount,obj2.retainCount);
obj1.retainObject = obj2; //因爲retainObject是retain屬性所以obj2指向的堆內存對象的引用計數要加1 ,此時爲2
obj2.retainObject = obj1; //因爲retainObject是retain屬性所以obj1指向的堆內存對象的引用計數要加1 ,此時爲2
NSLog(@"after");
NSLog(@"obj1 retainCount=%ld obj2 retainCount=%ld",obj1.retainCount,obj2.retainCount);
//當改函數運行結束返回,此時obj1和obj2的聲明週期也就結束了
//內存管理原則什麼作用範圍內創建就在什麼範圍內釋放
[obj1 release]; //obj1指向的堆內存對象的應用計數減1,此時引用計數爲1,此時的引用計數的所有者爲obj2的retainOject屬性
[obj2 release]; //obj2指向的堆內存對象的應用計數減1,此時引用計數爲1,此時的引用計數的所有者爲obj1的retainOject屬性
// 這個函數都結束了,堆內存中還存在兩個相互引用的對象,沒有棧上的指針變量引用它們,無法獲得它們,就無法釋放它們,這樣就找出了內存泄漏
2015-01-18 00:12:13.260 MemoryManager[1186:56593] before
2015-01-18 00:12:13.260 MemoryManager[1186:56593] obj1 retainCount=1 obj2 retainCount=1
2015-01-18 00:12:13.261 MemoryManager[1186:56593] after
2015-01-18 00:12:13.261 MemoryManager[1186:56593] obj1 retainCount=2 obj2 retainCount=2
Block_copy(<#...#>)也會造成循環應用,如果在block中使用了一些block外部的變量,你需要通過__weak來修飾弱引用這樣纔不會造成循環引用。
如:
__weak ViewController *weakVc = self;
dispatch_async(dispatch_get_main_queue(), ^{
weakVc.view.backgroundColor =[UIColor redColor];
});
二.屬性被copy,retain,strong,assign修飾的含義
#import <Foundation/Foundation.h>
@interface CycleRetain : NSObject
@property (nonatomic,assign)id retainObject;
@end
CycleRetain *obj1 = [[CycleRetain alloc]init];//此時 obj1指向的堆對象的引用計數爲1
CycleRetain *obj2 = [[CycleRetain alloc]init];//此時 obj2指向的堆對象的引用計數爲1
NSLog(@"before ");
NSLog(@"obj1 retainCount=%ld obj2 retainCount=%ld",obj1.retainCount,obj2.retainCount);
obj1.retainObject = obj2; //因爲retainObject是assign屬性所以obj2指向的堆內存對象的引用計數此時爲1
obj2.retainObject = obj1; //因爲retainObject是assign屬性所以obj1指向的堆內存對象的引用計數此時爲1
NSLog(@"after");
NSLog(@"obj1 retainCount=%ld obj2 retainCount=%ld",obj1.retainCount,obj2.retainCount);
MemoryManager[633:14446] obj1 retainCount=1 obj2 retainCount=1