文明转转和评论是对自己的尊重也是对学者的鼓励,谢谢
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