OC 基础-Block类型
OC基础-Block(3)Block的类型
Block有三种类型,可以通过调用class方法或者isa指针查看具体类型,最终都是继承NSBlock类型
NSGlobalBlock (NSConcreteGlobalBlock) 没有访问auto变量
NSStackBlock (NSConcreteStackBlock) 访问了auto变量
NSMallocBlock (NSConcreteMallocBlock) __NSStackBlock调用了copy
看图更清楚
一般全局变量存于数据段,alloc出来的存于堆段,局部变量存于栈段(一般数据不宜很大),类对象内存一般存于数据段
Block做为函数返回值的时候,(ARC情况下)系统会自动给block做copy处理
每一种类型的block调用copy后的结果如下图所示
Block类型 副本源的配置存储域 复制效果
_NSConcreteStackBlock 栈 从栈复制到堆
_NSConcreteGlobalBlock 程序的数据区域 什么也不用做
_NSConcreteMallocBlock 堆 引用计数增加
栈上的内存系统会自动回收
栈空间的block 不会对 对象进行强引用
堆空间的block 可能会对对象产生强引用:
如果是weak指针,不会强引用
如果是strong指针,会强引用
堆上的内存是由程序员控制,所以一般将block 拷贝到堆上,让程序员控制他与内部变量的生命周期
//上代码
1.NSGlobalBlock
#import <Foundation/Foundation.h>
typedef void(^MJBlock)(void);
MJBlock myBlock(){
return ^{
NSLog(@"-----------");
};
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
MJBlock block = myBlock();
block();
NSLog(@"%@",[block class]);
}
return 0;
}
//打印结果
2021-03-07 21:19:31.897780+0800 DoBlock[74885:2090486] -----------
2021-03-07 21:19:31.898430+0800 DoBlock[74885:2090486] __NSGlobalBlock__
原因分析:因为里面没有访问到任何的auto变量,所以MJBlock为NSGlobalBlock
代码2.NSMallocBlock
#import <Foundation/Foundation.h>
typedef void(^MJBlock)(void);
MJBlock myBlock(){
int age = 20;
return ^{
NSLog(@"-----------age%d",age);
};
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
MJBlock block = myBlock();
block();
NSLog(@"%@",[block class]);
}
return 0;
}
//打印结果
2021-03-07 21:23:36.045133+0800 DoBlock[74961:2094241] -----------age = 20
2021-03-07 21:23:36.045757+0800 DoBlock[74961:2094241] __NSMallocBlock__
原因分析:咦,不是访问了auto变量,应该是NSStackBlock吗?其实是Block做为返回值,ARC环境下默认帮我们做了一次copy处理,__NSStackBlock调用了copy处理所以就是NSMallocBlock类型咯
此时我们做一个总结
在ARC环境下,编译器会根据情况自动将栈上的block复制到堆上,比如以下情况
1)block作为函数返回值时
2)将block赋值给__strong指针时
int main(int argc, const char * argv[]) {
@autoreleasepool {
int age = 50;
MJBlock block = ^{
NSLog(@"----- = %d",age);
};//强引用
NSLog(@"%@",[block class]);
}
return 0;
}
//打印结果:2021-03-07 21:39:42.777653+0800 DoBlock[75249:2109355] __NSMallocBlock__
int main(int argc, const char * argv[]) {
@autoreleasepool {
int age = 30;
NSLog(@"%@",[^{
NSLog(@"%d",age);
} class]);
}
return 0;
}
//因为只是引用了auto变量所以
//打印结果:2021-03-07 21:40:37.273735+0800 DoBlock[75269:2110555] __NSStackBlock__
3)block作为Cocoa API中方法名含有usingBlock的方法参数时
NSArray * array = @[];
[array enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
}];
//block最终会搬到堆上面去
4)block作为GCD API的方法参数时
所以在这些情况下block类型都为NSMallocBlock类型。
Tip:
在使用clang转换OC为C++代码时,可能会遇到以下问题
cannot create __weak reference in file using manual reference
解决方案:支持ARC、指定运行时系统版本,比如
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m