OC对象 - Block的类型

70 阅读2分钟

OC对象 - Block的类型

1. Block有三种类型

  • 全局: __NSGlobalBlock__( _NSConcreteGlobalBlock )
  • 栈区:__NSStackBlock__ ( _NSConcreteStackBlock )
  • 堆区:__NSMallocBlock__ ( _NSConcreteMallocBlock )

1.1 它们最终都是继承自NSBlockNSBlock则是继承自NSObject

1.2 它们位于程序的不同内存区域

2. 不同类型的Block

2.1 特点

block类型环境
NSGlobalBlock没有访问auto变量
NSStackBlock访问了auto变量
NSMallocBlock__NSStackBlock__调用了copy

2.2 每一种类型的block调用copy之后

3 验证

3.1 打印black类型

我们逐级打印blackclasssuperclass,可以看到最终是继承自NSBlockNSBlock则是继承自NSObject

3.1 验证不同类型的Block

我们已经知道,访问了auto变量的block是NSStackBlock类型,__NSStackBlock__调用了copy后是NSMallocBlock

当运行如下代码,却发现访问了 auto 变量的 block 却是__NSMallocBlock__

3.2 ARC和MRC

这是因为,现在项目默认是启用ARC的,ARC下会自动帮我们添加copy操作(具体规则后面章节讲),我们先把项目设置为MRC

重新运行 和我们预期的一样

4. block的copy

4.1 在ARC环境下,编译器会根据情况自动将栈上的block复制到堆上,比如以下情况

  • block作为函数返回值时
  • 将block赋值给__strong指针时
  • block作为Cocoa API中方法名含有usingBlock的方法参数时
  • block作为GCD API的方法参数时

4.1.1 block作为函数返回值时

通过下面示例,验证了block作为函数返回值时是__NSMallocBlock__,直接创建打印则是__NSStackBlock__

4.1.2 将block赋值给__strong指针时

  • 创建ZSXPerson类,并声明一个strong修饰的block属性
@interface ZSXPerson : NSObject

@property (strong, nonatomic) void (^block)(void);

@end
  • 初始化ZSXPerson实例对象person,并把block赋值给person.block

此时的 block 是__NSMallocBlock__

4.1.3 block作为Cocoa API中方法名含有usingBlock的方法参数时

示例:

4.1.4 block作为GCD API的方法参数时

示例:

4.2 MRC下block属性的建议写法

@property (copy, nonatomic) void (^block)(void);

4.3 ARC下block属性的建议写法

@property (strong, nonatomic) void (^block)(void); @property (copy, nonatomic) void (^block)(void);

@oubijiexi