IOS开发之Block(二)
前言
我目前在XX大厂实习,正在学习iOS开发,在此分享我的学习心得和一些实践经验。如果文中有任何不准确之处,欢迎指正。
正文
block有3种类型,可以调用class方法或者isa指针查看具体的类型,最终都继承NSBlock类型
NSGlobalBlock_ (NSConcreateGlobalBlock) 没有访问auto变量 程序的数据区域 copy:什么也不做
NSStackBlock (NSConcreateStackBlock) 访问了auto变量 栈 copy:从栈复制到堆
NSMallocBlock (_NSConcreteMallocBlock) __NSStackBlock__调用了copy copy:引用计数增加
来一张图片:
由于后面用到ARC/MRC环境,在Xcode设置:
#import <Foundation/Foundation.h>
void (^block123)(void);
void test(){
int age = 100;
block123 = ^{
NSLog(@"block %d ",age);
};
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
// Global:没有访问auto变量 放在数据段
void (^block)(void) = ^{
NSLog(@"Hello world");
};
NSLog(@"%@",[block class]); // __NSGlobalBlock__
// stack:访问了auto变量
int age = 10;
void (^block1)(void) = ^{
NSLog(@"Hello world - %d",age);
};
NSLog(@"%@",[block1 class]); // ARC:__NSMallocBlock__
int weight = 10;
void (^block2)(void) = [^{
NSLog(@"Hello world - %d",weight);
} copy]; // 会在堆上创建内存存放和栈上相同的值
NSLog(@"%@",[block2 class]);
test();
block123();
}
return 0;
}
输出:
上面都是MRC环境下
输出:
__NSGlobalBlock__
__NSStackBlock__
__NSMallocBlock__
block -1074793912
在这里输出" block -1074793912 "因为在MRC环境下离开其作用域导致的
ARC环境下,编译器会根据情况自动将栈上的block复制到堆上,以下情况
1、block作为函数返回值时
代码:
#import <Foundation/Foundation.h>
typedef void (^Block)(void);
Block myBlock(){
// ARC release也不需要我们调用
return ^{
NSLog(@"hello world");
};;
}
Block myBlock2(){
int age = 10;
return ^{
NSLog(@"hello world %d",age);
};;
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
Block block1 = myBlock();
block1();
NSLog(@"%@",[block1 class]); // __NSGlobalBlock__ 进行copy什么也不做
Block block2 = myBlock2();
block2();
NSLog(@"%@",[block2 class]); // __NSMallocBlock__
}
return 0;
}
2、将block赋值给__strong指针时
#import <Foundation/Foundation.h>
typedef void (^Block)(void);
int main(int argc, const char * argv[]) {
@autoreleasepool {
int age = 10;
Block block = ^{
NSLog(@"hello world %d",age);
};
NSLog(@"%@",[block class]); // ARC: __NSMallocBlock__ MRC: __NSStackBlock__
NSLog(@"%@",[^{ // __NSStackBlock__ 没有强指针指向
NSLog(@"hello world %d",age);
} class]);
NSLog(@"%@",[^{ // __NSGlobalBlock__
NSLog(@"hello world %d");
} class]);
}
return 0;
}
3、block作为Cocoa API中方法名含有usingBlock的方法参数时
#import <Foundation/Foundation.h>
// 像这种
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSArray* array = @[];
[array enumerateObjectsUsingBlock:<#^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop)block#>]
}
return 0;
}
4、block作为GCD API的方法参数时
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
<#code to be executed once#>
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(<#delayInSeconds#> * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
<#code to be executed after a specified delay#>
});
}
return 0;
}