内存管理的一些总结:
1、全局类型的变量初始化的时候 变量名=[[alloc]init],最后在delloc里面释放,如果一些变量必须要用静态方法创建,那么可以变量名=[[类 静态方法]retain],在delloc释放
2、局部类型的变量初始化的时候如果是alloc创建的,那么在使用完成后release,如果是类调用静态方法创建的,不管他
3、使用委托时,如果出现了循环引用,不能用retian必须用assign
可变数组一般用retain
原因:
如果一个可变数组用copy如:@property (nonatomic,copy)NSMutableArray *arr;
通过copy出来的内存是不可变的,那么,当arr用addObject的时候就报错了
.h文件
//
// ZQAppDelegate.h
// Arc
//
// Created by mac on 15-5-13.
// Copyright (c) 2015年 KangZhiQiang. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface ZQAppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (nonatomic,retain) UIView *myView;
@property (nonatomic,assign) UIView *myView0;
@property (nonatomic,copy)NSMutableArray *arr;
@property (nonatomic,retain) UIButton *myBtn;
@end
.m文件
//
// ZQAppDelegate.m
// Arc
//
// Created by mac on 15-5-13.
// Copyright (c) 2015年 KangZhiQiang. All rights reserved.
//
#import "ZQAppDelegate.h"
#import "ZQViewController.h"
@implementation ZQAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
ZQViewController *zq=[[ZQViewController alloc]init];
self.window.rootViewController=zq;
//只要我们自己alloc new retain copy这些内存的时候,他的引用计数会增加,并且只要我们自己让他的引用计数减少时候,他才会减少,系统不会让其减少
UIView *vi=[[UIView alloc]init];
//输出引用计数
NSLog(@"%d",[vi retainCount]);
//release是异步过程,比较安全的写法是在内存释放完成后把指针置为nil
[vi release];
vi=nil;
[vi release];
[vi release];
[vi release];
[vi release];
vi=nil;//空指针可以做任何事情,并且可以无限release
vi.backgroundColor=[UIColor redColor];
vi.tag=5;
vi.frame=CGRectMake(0, 0, 30, 30);
NSLog(@"%d",[vi retainCount]);
NSLog(@"%d",[vi retainCount]);
NSLog(@"%d",[vi retainCount]);
NSLog(@"%d",[vi retainCount]);
//内存管理:谁创建谁释放
UIView *vi2=[[UIView alloc]init];
NSLog(@"%d",[vi2 retainCount]);//此时输出1
//当一个视图放在另一个视图上得时候,系统会让其引用计数增加
[self.window addSubview:vi2];//此时系统让其应用计数增加,所以我们不用管
NSLog(@"%d",[vi2 retainCount]);//此时输出2
[vi2 release];
//当一个视图从父视图中移除的时候,系统会让其引用计数减少
[vi2 removeFromSuperview];
//放入数组 放入导航器 UIAlertView show的时候,系统都会让其引用计数增加,当从数组中移除 从导航器重移除 UIAlertView 点击按钮消失时候系统也会让其引用计数减少
//当一个类的内存通过一个类的静态方法创建的时候,他的引用计数也为1,只不过这块内存是自动释放的
UIButton *btn=[UIButton buttonWithType:UIButtonTypeSystem];
NSLog(@"btn%d",[btn retainCount]);
[btn addTarget:self action:@selector(onClick:) forControlEvents:UIControlEventTouchUpInside];
btn.frame=CGRectMake(0, 0, 100, 40);
btn.backgroundColor=[UIColor redColor];
[self.window addSubview:btn];
NSLog(@"btn%d",[btn retainCount]);
//总结:
//(1)局部变量是对象类型,如果创建的时候是alloc new copy retain 必须要在使用完成后release
//(2)局部变量是对象类型,如果是类调用静态方法创建的时候,不能写release
UIView *vi3=[[[UIView alloc]init]retain];//增加2
NSLog(@"888>>>>%d",[vi3 retainCount]);
UIView *vi4=[[[[UIView alloc]init]retain]autorelease];//增加2,又自动减1
NSLog(@"vi4>>>>%d",[vi4 retainCount]);
//全局类型的变量因为我们要在多个方法中进行访问,所以这个对象不能够是自动释放的,需要手动创建
_myView=[[UIView alloc]init];
//此处button的创建是个特例,因为我们只能用静态方法创建,那么此时其内存是自动释放,那么我们要在其他方法里边用的时候可能已经被释放了,所以我们应该强制的给其加个retain,让其引用计数加1,这样就不会出现程序崩溃的问题了,但是既然我们让引用计数加1,我们就需要再dealloc方法中release
_myBtn=[[UIButton buttonWithType:UIButtonTypeSystem]retain];
[self.window addSubview:_myBtn];
UIView *vi5=[[UIView alloc]init];//alloc,vi5的引用计数+1
self.myView=vi5;//myView是retain,所以两个对象的引用计数都+1,变成2
NSLog(@"%p>>>>>%p>>>>%d",self.myView,vi5,[vi5 retainCount]);
//两个内存地址想的,引用计数都为2
UIView *vv=[[UIView alloc]init];
self.myView=vv;//此处调用下边的setMyView方法,让自身减1.然后又用retain+1
NSLog(@"110====%p>>>>>%p>>%d>>>%d",self.myView,vv,[vi5 retainCount],[vv retainCount]);
两个内存地址想的,10====0x8d8fa50>>>>>0x8d8fa50>>1>>>2
UIView *vvv=[[UIView alloc]init];
self.myView=vvv;
NSLog(@"%p>>>>%p>>>>>%d>>>>%d",self.myView,vvv,[vv retainCount],[vvv retainCount]);
UIView *vv0=[[UIView alloc]init];
self.myView0=vv0;//myView0是assign,所以两个对象的引用计数都不变,都为1
NSLog(@"110====%p>>>>>%p>>%d>>>%d",self.myView0,vv0,[self.myView0 retainCount],[vv0 retainCount]);
//110====0x8d98040>>>>>0x8d98040>>1>>>1
UIView *vvv0=[[UIView alloc]init];
self.myView0=vvv0;//myView0是assign,所以两个对象的引用计数都不变,都为1
NSLog(@"%p>>>>%p>>>>>%d>>>>%d",self.myView0,vvv0,[vv0 retainCount],[vvv0 retainCount]);
//0x8d90f00>>>>0x8d90f00>>>>>1>>>>1
//个人理解,对不可变数组系统自动用浅copy,然后让两个指针指向同一块内存空间,原因是不可变数组不会改变,所以让两个指针指向同一个也不会出现问题,而对于可变数组,系统会自动再分配一块内存空间,两块空间中的内容相同,这样当一个内存中的内容改变的时候,也不影响另一块的内容
NSArray *array=[[NSArray alloc]initWithObjects:@"0", nil];
self.arr=array;//arr为copy,array是不可变数组,所以为浅copy,两个指针指向同一块内存空间,引用计数+1.变成2
NSLog(@"%p>>>>%p>>>>%d",self.arr,array,[array retainCount]);
//0x8d98d30>>>>0x8d98d30>>>>2
NSMutableArray *muArr=[[NSMutableArray alloc]initWithObjects:@"0", nil];
self.arr=muArr;//arr为copy,muArr是可变数组,所以为深copy,两个指针指向不同内存空间,引用计数都为1
NSLog(@"%p>>>>%p>>>%d>%d",self.arr,muArr,[self.arr retainCount],[muArr retainCount]);
//0x8d94270>>>>0x8d6db70>>>1>1
return YES;
}
//assign
- (void)setMyView0:(UIView *)myView0{
if (_myView0!=myView0) {
_myView0=myView0;
}
}
//retain 的set方法
- (void)setMyView:(UIView *)myView{
if (_myView!=myView) {
[_myView release];
_myView=[myView retain];
}
}
//copy
- (void)setArr:(NSMutableArray *)arr{
if (_arr!=arr) {
[_arr release];
_arr=[arr copy];
}
}
//当一个类的对象over的时候,就会调用其dealloc方法,在这个方法里边要去释放属性
- (void)dealloc{
//此处要先释放全局的属性,然后再调用super的dealloc方法,比如一颗大树创建完成后,我们在其上边加了枝叶,我们应该先把其枝叶去掉之后再把大树的树干去掉
[_myView release];
[_myBtn release];
[super dealloc];
}
- (void)onClick:(UIButton *)btn{
}
@end