您的位置:首页 > 移动开发 > IOS开发

iOS学习之block(一)

2016-03-15 13:46 330 查看
这两天由于面试问到了block一些问题,比如block是如何引起循环应用的(我为什么要关心循环引用啊?答案是:循环引用会使内存消耗过高,性能变差,app闪退等)。

循环引用:




借鉴了苹果官方文档:https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html#//apple_ref/doc/uid/TP40014097-CH20-ID48

解释:变量john强引用Person对象,变量unit4A强引用了Apartment对象,当给Person对象的属性Apartment赋值后,Person实例就又强引用了Apartment实例,当给Apartment对象的属性Person赋值的时候,它又强引用了Person实例,即使给john=nil,unit4A=nil,Person和Apartment之间还存在强引用,无法释放。ARC对强引用无效的。

首先回顾一下block的基础知识:

block类型的语法与函数指针近似。

void (^someBlock)() = ^ {

//block implementation here

}

解释:上面定义了一个返回值为空,无参数的block,“^”符号表示block类型定义,someBlock为变量名,也就是上面定义了一个变量名为someBlock的变量。变脸名写在中间是挺奇怪的看上去(因为正常类型定义都是int a,变量名放在类型后面)。

block的强大之处在于:在声明它的范围内,所有变量都可以为其捕获。

如果block捕获的变量是对象的话,block会自动保留它。

如果将block定义在类的实例方法中,那么除了可以访问所有的实例变量之外,还可以使用self变量。

block总能修改实例变量,所以不用加__block。

如果将值赋值给block中截获的自动变量,就会产生编译错误;调用更改对象的方法则不会。在这种情况下,需要给截获的自动变量附加__block说明符。

如果通过读取或写入操作捕获了实例变量,那么self也就捕获了,因为实例变量与self所指代的实例关联在一起的。

(二)全局block、栈block、堆block

定义block的时候,其所占的内存区域是分配在栈的。也就是说,block只在定义它的那个范围内有效。

void (^testBlock)();
if (/* some condition */) {
testBlock = ^ {

};
} else {
testBlock = ^ {

};
}
testBlock();


定义在if及else中的两个block都是分配在栈内存中的。编译器会给每个块分配好栈内存,然而等它离开相应的范围之后,编译器有可能把分配给block的内存覆写掉(栈block执行后内存会被回收,即使retain也没用)。这样的代码能保证编译,但是会时灵时不灵,而且如果内存被覆写掉会使程序崩溃。

那么改怎么解决这个问题呢?可以给block发送copy消息以拷贝之。这样的话,就可以把block从栈复制到堆,就可以它的那个范围之外使用了。而且,一旦复制到堆上后,block就成了带有引用计数的block了,后续的复制操作都不会真的复制,只是递增block的引用计数。如果不再使用这个block,就将其释放掉。ARC会自动释放,手动管理内存手动释放,发送release消息。(release,retain操作都是针对堆上的block(NSMallocBlock),尽管retainCount始终是1,但内存管理中仍会增加或减少计数,所以copy后不会生成新的对象,)

除了栈block和堆block外,还有全局block。这种block不会捕获任何状态,运行时也不需要状态来参与。block所使用的整个内存区域,在编译时就已经确定了,不需要在栈中每次进行创建。copy操作对其只是空操作,因为全局block不能被系统所回收。

注:即我们可以通过block是否引用外部变量来区分是否是全局block

(三)怎么在block内部改变变量

(1)在这个变量前面加上__block

(2)在这个变量前面加上static变为静态变量或者静态全局变量

(3)把这个变量定义为全局变量

(四)如果block所捕获的对象直接或间接保留了block本身,那么就要当心保留环的问题。

参考:http://devtang.com/2013/07/28/a-look-inside-blocks/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: