OC 底层原理笔记

8OC使用原理 -8-block-本质,类型,copy属性详解

2020-01-20  本文已影响0人  zysmoon

1.Block的本质

1653926-e16325544d59c7df.png 1653926-c1dd77301a996274.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;
}

1653926-164d8fe25b3a121f.png
2.block的变量捕获(capture)
1653926-d158d0bd008f6b67.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;
}

运行结果

1653926-5c061022aba45eb2.png
3.block的类型
1653926-24060eddacbac784.png 1653926-1c94adda24328056.png 1653926-554a876b4e966c44.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]
    );
}

运行结果如下

1653926-21fb125822f77ec6.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]);
}

打印结果

1653926-1e441e8b323b6c1c.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;
}

运行结果

1653926-dd660159f77dff26.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;
}

打印结果

1653926-76c4fbacd99bd6b1.png 1653926-3459356b2391d606.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建议写法

本文参考:
路飞_Luck (https://www.jianshu.com/p/07f7b96bb03f)
以及借鉴MJ的教程视频
非常感谢.


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

上一篇下一篇

猜你喜欢

热点阅读