Block
block本质是一个匿名函数,底层是一个结构体,里面包含属性成员、isa函数指针等。
block主要是作为回调使用。
__block修饰符,主要作用是把栈上数据复制到堆上。在block函数体中,__block修饰的常量属于指针引用,而没有修饰符的常量属于值引用。
int a = 10;
__block int b = 10;
block1 = ^{
NSLog(@"%@",a); //输出a为10
NSLog(@"%@",b); //输出b为20
}
a = 20;
b = 20;
block2 = ^{
NSLog(@"%@",a); //输出a为20
NSLog(@"%@",b); //输出b为20
}
block在声明的时候,就会把外部变量复制。所以block1复制的a是值,所以block1输出的a为10,而block2输出的值为20;而block1复制的b是指针,所以b重新赋值的时候,block1中的b也变了,输出b为20,而blcok2同理。
堆 栈
堆:内存大、内存地址不连续、由程序员管理
堆的内存地址采用的是链表存储,效率较慢,分配方式只有动态分配
栈:内存小、内存地址连续、由系统管理、先进先出
栈的效率较快,分配方式由静态分配和动态分配
静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。
栈的内存大小一般为2M
栈中储存是常量和指针。
比如局部变量 M* m = [[M alloc]init];
m的指针是存储在栈上的,而m的值是存储在堆上的。
栈另一个名称叫做函数栈,局部变量存放在栈中,整个程序都是执行在主函数中,每次调用一个函数,都是压入一个栈区。
比如函数A调用函数B,会将函数A中的变量都压入栈区,调用函数B的时候会将整个函数A栈区作为一个模块,之后再把函数B中的变量压入栈中,当B执行完成,不再被调用,那么函数B的栈区出栈。
一个函数利用GCD进行延迟处理数据,外部自由可控是否延迟处理执行,变为一个通用函数。
- (void)execAfter:(NSInteger)sec block:(void(^)(void))block {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
block();
});
}
以下几种方式:
- (void)execAfter:(NSInteger)sec handle:(Handle*)handle block:(void(^)(void))block {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (handle.isExec) {
return;
}
block();
});
}
- (Handle*)execAfter:(NSInteger)sec block:(void(^)(void))block {
Handle* h = [Handle new];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (h.isExec) return;
block();
});
return h;
}