retaincount是引用计数的意思。
使用release使retaincount-1,使用retain使retaincount+1,当retaincount等于0的时候,该对象会被释放掉。
非ARC内存管理:
(1)如果调用了alloc\new\copy产生了一个新对象,最后肯定要调用一次release或者autorelease。
(2)如果让一个对象做了retain操作(计数器+1),最后肯定要调用一次release或者autorelease。
(3)内存管理原则是有加有减。
在内存管理时会碰到下面的几个问题:
(1)野指针
可将对象赋值为nil,可以避免野指针的出现。
[p release];
p = nil;
p.age = 30;//相当于 [nil setage:30],这样就不会造成野指针,如果不加第二行代码,会造成野指针。
(2)内存泄露
不被使用的对象,一直在内存中没有被销毁。会造成内存泄露
[p retain]; //retaincount=2
[p retain]; //retaincount=3
[p release]; //retaincount=2
上面三行代码代码会导致内存泄露,因为p对象没有完全释放,他的retaincount不等于零。
p = nil;
[p release]; //此行代码相当于[nil release],但是他并没有让retaincount 进行-1的操作
(3)set方法的内存管理写法
- (void) setCar: (Car *) car
{
if ( _Car != car)
{
[_Car release];
_Car = [Car retain];
}
}
接下来是autoreleasepool,也就是自动释放池:
对象存入到自动释放池中,当这个池子被销毁时,会对池中的对象进行一次release操作,
在一个项目中会有一个默认的autoreleasepool,在项目文件main.m里面,实际上他是一个死循环。一直到程序终止才被销毁。
int main(int argc,char * argv[]) {
@autoreleasepool {
returnUIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegateclass]));
}
}
需要注意的是:
(1) 只有在autoreleasepool作用域中,调用autorelease方法,才能将对象添加到自动释放池中。
@autoreleasepool {
Car *c = [ [ [ Car alloc ] init ] autorelease ];
}
(2)函数返回值,不能直接用release,如果直接用release可能会造成野指针的错误,这时候可以选择使用autorelease。(3)系统对象本身都是autorelease,不能用对齐使用release。例如不能 : NSString *str = @"str";[str release];
接下来是集合手动管理内存的方法:
(1)当对象添加进数组的时候,会retain一次。
[array addobject:p];
(2)当对象删除的时候,会release一次。
[arrat removeobject:p]
(3)当数组release的时候,会release一次。
block的内存管理:
block内存管理默认是在栈中,开发人员不需要去管理block内存
Dog *d = [[Dog alloc]init];
void (^Myblock)() = ^
{
NSLog(@"%@",d.age);
};
Myblock();
Block_copy(Myblock);
//Block_release(Myblock);
在上面的Block_copy(Myblock)这一句,对block进行了copy操作 ,block的内存会搬到堆里面,Dog的retainCount会加1,
Block_release(Myblock)这一句虽然会把block进行一次release操作,但是Dog的retainCount仍然是2.
在这里可以通过[ d retainCount]查看Dog的retainCount到底有多少。
为了解决这个问题,在非ARC情况下,可以在定义Dog的时候,加上__block,在ARC情况下,可以加上__weak或者__unsafe_unretained解决这个问题。
__block Dog *d = [[Dog alloc]init];
__weak Dog *d = [[Dog alloc]init];
__unsafe_unretained Dog *d = [[Dog alloc]init];
还有就是如果一个对象拥有一个block,是不能用assign参数,因为这样block在栈里面,不能确保block会存在,只能用copy,这样就把block放到堆里面,
需要注意的是如果此时实在非ARC情况下,需要在dealloc方法里面,使用Block_release(Myblock)进行一次release操作。
除此之外是集合在ARC下的内存分析:
(1)当一个对象被存入集合的时候,默认是保存强指针
(2)array = nil;//数组被销毁
(3)[array removeobject:p]; --------> p=nil; ------------>p被销毁