iOS底层基础知识iOS面试知识点iOS 的那些事儿

iOS-底层原理(8)-block-本质,类型,copy属性详解

2018-09-01  本文已影响102人  路飞_Luck

1.Block的本质

image.png image.png

代码佐证

struct __main_block_desc_0 {
    size_t reserved;
    size_t Block_size;
};

struct __block_impl {
    void *isa;
    int Flags;
    int Reserved;
    void *FuncPtr;
};

// block底层结构体
struct __main_block_impl_0 {
    struct __block_impl impl;
    struct __main_block_desc_0* Desc;
    int age;
};

// 1.block结构体
void test1() {
    int age = 10;
    
    // 定义block
    void(^block)(int, int) = ^(int a, int b){
        NSLog(@"this is a block! -- %d", age);
        NSLog(@"a = %d, b = %d",a,b);
    };
    
    struct __main_block_impl_0 *blockStruct = (__bridge struct __main_block_impl_0 *)block;
    block(100,200);
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        
        // 1. block结构体
        test1();
    }
    return 0;
}
image.png
2.block的变量捕获(capture)
image.png

代码例子如下:

// 捕获变量类型
void (^block)(void);

void blockTest() {
    int age = 10;
    static int height = 10;
    
    block = ^ {
        NSLog(@"age is %d, height is %d", age, height);
    };
    
    age = 20;
    height = 20;
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        blockTest();
        block();
    }
    return 0;
}

运行结果

image.png
3.block的类型
image.png image.png image.png

代码例子如下

// 4.block的类型
int weight = 100;
void (^block)(void);

void blockClassType() {
    // 堆:动态分配内存,需要程序员申请申请,也需要程序员自己管理内存
    static int age = 10;
    // 局部static变量
    int height = 10;
    
    // Global:没有访问auto变量
    void(^block1)(void) = ^ {
        NSLog(@"block1");
    };
    // Globa2:访问static变量
    void(^block2)(void) = ^ {
        NSLog(@"block2 - age = %d",age);
    };
    // Globa3:访问全局变量
    void(^block3)(void) = ^ {
        NSLog(@"block3 - weight = %d",weight);
    };
    
    // Stack:访问了auto变量
    void (^block4)(void) = ^{
        NSLog(@"block4 - height = %d", height);
    };
    
    // NSMallocBlock - 对StackBlock做copy操作
    block = [^{
        NSLog(@"block---------%d", height);
    } copy];
    [block release];
    
    NSLog(@"%@ %@ %@ %@ %@",
          [block1 class],
          [block2 class],
          [block3 class],
          [block4 class],
          [block class]
    );
}

运行结果如下

image.png
4. 数据存储位置

代码例子如下

// 5.数据存储位置
int age = 100;
void dataLocationTest() {
    int a = 10;
    
    NSLog(@"数据段:age %p", &age);
    NSLog(@"栈:a %p", &a);
    NSLog(@"堆:obj %p", [[NSObject alloc] init]);
    NSLog(@"数据段:class %p", [Person class]);
}

打印结果

image.png
5.block的copy

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

代码例子如下

// 定义一个block
typedef void(^CSBlock)(void);

// 定义一个返回blcok的函数
CSBlock myBlock() {
    int age = 10;
    return ^{
        NSLog(@"age = %d",age);
    };
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        
        // 1.block作为函数返回值
        CSBlock block = myBlock();
        block();
        NSLog(@"%@",[block class]);
    }
    return 0;
}

运行结果

image.png
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // 2.block有被强指针引用
        // ARC - 环境下 block - __NSMallocBlock__
        // MRC - 环境下 block - __NSStackBlock__
        int age = 10;
        CSBlock block = ^{
            NSLog(@"---------%d", age);
        };
        NSLog(@"%@", [block class]);
    }
    return 0;
}

打印结果

ARC.png MRC.png
// 3.block作为Cocoa API中方法名含有usingBlock的方法参数时
NSArray *array = [NSArray array];
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
            
}];
// 4.block作为GCD API的方法参数时
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{            
});
block建议写法

本文参考借鉴MJ的教程视频,非常感谢.


项目演示代码如下
iOS_block_本质
iOS-block-copy


更多block相关文章

iOS-copy底层原理之auto变量

iOS-block底层原理详解之__block属性

iOS-block底层原理之循环引用详解

上一篇下一篇

猜你喜欢

热点阅读