iOS block 小结

来源:互联网 发布:xampp mac使用教程 编辑:程序博客网 时间:2024/06/04 20:10

iOS block在使用过程中如不小心会出现些问题,如循环引用、崩溃等,下面结合自己的实际使用做一下总结。

首先,先看一下llvm实现block的源码(这个很重要):http://clang.llvm.org/docs/Block-ABI-Apple.html#objective-c-extensions-to-blocks

其实block就是用c语言实现的一个struct,里面包含了block的类型:NSConcreteStackBlockNSConcreteMallocBlock、NSConcreteGlobalBlock。

NSConcreteStackBlock:在MRC的内存管理模式下,使用了上下文变量的block是这种类型,这类型通过retain是hold不住的,因为它是分配在stack内存空间的,生命周期跟局部变量一样,只在作用域内有效。通过copy,系统会在堆内分配空间,把它拷贝到堆,转变为NSConcreteMallocBlock

NSConcreteMallocBlock:在ARC模式下,可能苹果出于防崩溃考虑,不再存在NSConcreteStackBlock,使用了上下文变量的block一律是NSConcreteMallocBlock,所以在ARC模式下,用retain和copy的效果是一样的。

NSConcreteGlobalBlock:没有用到上下文变量的block是这种类型。

一、关于崩溃:因为block实际是一个struct,所以在使用过程是必须先判断是否为NULL,在c语言中,使用NULL针指进行操作是会崩溃的。

二、关于引用循环:

先看一段代码:


typedef void(^Block)();

@interfaceTestClass : NSObject {

NSString *_innerVar;

}

@property(nonatomic, copy) Block testBlock;

@property(nonatomic, copy) NSString *propertyVar;

@end

@implement  TestClass 

- (void)func {

self.testBlock = ^{

NSLog("%@", self.propertyVar);

};

self.testBlock();

}

@end

类引用了testBlock, testBlock用到了TestClass的成员变量,系统在查找实例的成员变量时,必须先知道实例的地址,参照《深度探索c++对象模型》,所以testBlock会retain TestClass。这就是一个简单的引用的循环。比较难发现的一些引用循环:Class A里引用了一个成员变量Class B,ClassB里有个回调block,

在Class A里设置Class B的block,而这个block又引用了Class A。

比较常用的破引用循环的方法:

1、在创建block之前使用__weak type(self) weakSelf = self;在block里使用weakSelf,不要用self

2、使用libextobjc开源库的weakify和strongify宏

不过使用这两种方法都要注意:block里用的都是property变量才不会有问题,如果直接用内部变量,比如例子的_innerVar,还是会retain TestClass的。如果实在要用内部变量可以通过指针的方式使用,如weakSelf->_innerVar。



0 0
原创粉丝点击