首先交代一下retain cycle ,和 产生retain cycle后咱们应该怎么处理。ios
1.retain cycle在block中是极易产生,block就是一段能够灵活使用的代码,你能够把它当作变量传递,赋值,甚至能够把它声明到函数体中。更加灵活的是它能够引用它的承载者(即就是block的运行环境),可是这样子就更容易产生retain cycle了 。就是简单说类比 子控件拥有父控件的引用,而父控件也拥有子控件的引用。这样相互引用。就不能造成父控件释放也能将子控件释放。这就形成一个内存泄露。程序员
2.及时打破这种retain cycle ARC :__strong , __weak ,__unsafe_unretained.存在有三个修饰字符,__strong 这要有调用,引用计数就要加1(retain) __unsafe_unretained 赋值给这个变量不会被retain,就是有这个字符修饰的对象,不能保证对象的可靠性。可能已经释放了。留下的只是一个野指针而已。__weak是ios5之后出现的类比与__unsafe_unretained,不一样的地方就是。它所持有对象被释放后会自动被赋值为nil。更加安全了。数组
正以下面的代码就是一个典型的retain cycle 安全
People *p=[People new];框架
p.dosth = ^(){函数
[p dosth];spa
[p release]; //由于dosth和p是相互持有关系,因此调用release也不能释放掉指针
};对象
1.咱们能够这样子处理(本身内心应该清楚,咱们不会再次回来调用这个方法了)ip
People *p=[People new];
p.dosth = ^{
[p dosth];
p.dosth=nil;
[p release]; //由于dosth和p是相互持有关系,因此调用release也不能释放掉
};
2.在ARC状况下
在ARC下, 如下几种状况, Block会自动被从栈复制到堆:
1.被执行copy方法
2.做为方法返回值
3.将Block赋值给附有__strong修饰符的id类型的类或者Blcok类型成员变量时
4.在方法名中含有usingBlock的Cocoa框架方法或者GDC的API中传递的时候.
利用
__block 将变量的地址考进了栈空间,这样子咱们就能够在Block中方便无比的调用最新的变量值了。由于block的空间也是在栈空间的.block内存是在栈上,(不须要程序员管理),当你这个做用域{方法}结束的时候,block被释放了.
__weak 被__weak修饰的变量,是不会被block retain的,可是也会同时引出提早释放变量的后果
3.在非ARC状况下
只要实现一个对周围变量没有引用的Block,就会显示为是NSGlobalBlock
若是其中加入了对局部变量的引用,就是NSStackBlock
若是你对一个NSStackBlock对象使用了Block_copy()或者发送了copy消息,就会获得NSMallocBlock (0)
1)NSGlobalBlock:retain、copy、release操做都无效;
2)NSStackBlock:retain、release操做无效,必须注意的是,NSStackBlock在函数返回后,Block内存将被回收。即便retain也没用。容易犯的错误是[mutableAarry addObject:stackBlock],(补:在ARC中不用担忧此问题,由于ARC中会默认将实例化的Block拷贝到堆上)在函数出栈后,从mutableAarry中取到的stackBlock已经被回收,变成了野指针。正确的作法是先将[stackBlock copy]到堆上,而后加入数组:[mutableAarry addObject:[[stackBlock copy] autorelease]]。支持copy,copy以后生成新的NSMallocBlock类型对象。
3)NSMallocBlock支持retain、release,虽然retainCount始终是1,但内存管理器中仍然会增长、减小计数。copy以后不会生成新的对象,只是增长了一次引用,相似retain;
4)Block_copy与copy等效,Block_release与release等效;
5)对Block不论是retain、copy、release都不会改变引用计数retainCount,retainCount始终是1;
6)尽可能不要对Block使用retain操做,不方便管理。
四、Block对objc对象的内存管理
staticObj、instanceObj、localObj、blockObj多种类型obj对象
主要是block被copy时其块中用到的变量的引用计数
1)非ARC
staticObj在内存中的位置是肯定的,因此Block copy时引用计数不会改变。
instanceObj在Block copy时并无直接让instanceObj对象自己引用计数加1,但却让self引用计数加1。因此在Block中能够直接读写instanceObj变量。
localObj在Block copy时,系统自动增长其引用计数。
blockObj在Block copy时引用计数也不会改变。
使用__block避免循环引用
__block 类 *对象 = self
void(^block)(void)= ^{
[blockSelf doSomething];
};
ARC下
只有在使用local变量时,block会复制指针,且强引用指针指向的对象一次。其它如全局变量、static变量、block变量等,block不会拷贝指针,只会强引用指针指向的对象一次。
block的循环引用,由于block在拷贝到堆上的时候,会retain其引用的外部变量,那么若是block中若是引用了它的宿主对象,那颇有可能引发循环引用。如:
self.myblock = ^{
[self doSomething];
};
使用__weak避免循环引用
Tips:
内存主要分为
1.栈 - 由编译器自动分配释放 里面的变量一般是局部变量 函数参数等
2.堆 - 通常由程序员分配释放,若程序员不释放,程序结束时可能由OS回收 alloc
3.全局区(静态区 static),全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另外一块区域。- 程序结束释放 static
People *p; People *p2 = nil;
4.另外还有一个专门放常量的地方。- 程序结束释放 NSString *lastName = @“xue”;
lastName = @“dkjs”;
五、方法区