block 堆 栈 总结

2022-05-07  本文已影响0人  风依旧_c080

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;
}
上一篇下一篇

猜你喜欢

热点阅读