Block深入浅出

280 阅读2分钟
Block的种类

Block分为三类 1.NSGlobalBlock: 静态区 2.NSMallocBlock: 堆 Block 3.NSStackBlock: 栈Block

    void(^fisrtBlcok)(void) = ^{
        NSLog(@"blcok");
    };
    NSLog(@"第一种%@",fisrtBlcok);

    NSInteger a = 10;
    void(^blcok)(void) = ^{
        NSLog(@"Hello block = %ld", a);
    };
    blcok();
    NSLog(@"第二种%@",blcok);
    
    NSLog(@"第三种Block: %@",^{
        NSLog(@"===%ld",a);
    });

解决Block循环引用方法
  1. Strong weak dance 这个不多说
    self.name = @"Eddiegooo";
    __weak typeof(self) weakSelf = self;
    self.testBlock = ^{
        __strong typeof(weakSelf) strongSelf = weakSelf;
        NSLog(@"%@", strongSelf.name);
    };

2.mrc: __block

    __block SecViewController *weakVC = self; //这里是重新copy了一份:
    //weakVC  ---> self ---> testBlock ---> weakVC = nil
    self.testBlock = ^{
        NSLog(@"%@",weakVC.name);
        //注意 必须置为nil
        weakVC = nil;
    };
    //这里必须还要掉用一下
    self.testBlock();  //调用Block, weakVC 就置nil了

3.把self当参数传递方式 Block 循环引用: self ---> block ---> self. self持有Block, Block持有self。 这时打破这个环即可解决。 self ----> block ----> vc

typedef void(^block)(SecViewController *vc);

@interface SecViewController ()

@property (nonatomic, strong) NSString *name;
@property (nonatomic, copy) block testBlock;

@end

    self.testBlock = ^(SecViewController *vc) {
        NSLog(@"%@", vc.name);
    };
    self.testBlock(self); //self当临时变量参数
深究Block原理

1.创建一个c文件 终端: vim block.c 写入C函数:

#include <stdio.h>
int main() {
  int a = 10;
void(^block)(void) = ^{
  printf("%d", a);
};

block();
return 0;
}

2.执行C函数 gcc block.c 输入一个a.out 的可执行文件。 ./a.out 执行它。 可以看到打印结果。 clang -rewrite-objc block.c 执行完得到block.cpp这个文件,打开看下什么东西。

文件.png
打开这个block.cpp 文件,一脸懵逼啊
懵逼文件.png

别怕慢慢看,其实这就是消息转发。 我们把文件拉倒最下面,就能找到main函数了。

main 函数.png
然后在点到文件里面去看下什么意思,值拷贝。

当我们把block.c 文件里,int a = 10, 前面加上__block ,在clang 一次。发现main函数变化很大哇:

__block 后的main函数.png
__block 这个就是浅copy作用。

Block应用:链式编程 + 函数式编程

链式编程:

//想要使用s链式编程,用点语法调用函数,返回IMP的第一个参数self
- (ViewController *)select {
    NSLog(@"Select");
    return self;
}

//返回一个Block参数
- (NSString *(^)(NSString *))where {
    NSString *(^block)(NSString *) = ^(NSString *word) {
        return [NSString stringWithFormat:@"向大家说:%@", word];
    };
    return block;
}

这样就可以调用点语法函数了。 NSLog(@"%@",self.select.where(@"niubi"));

函数式编程: y= f(x) ---> y = f(f(x));

//函数式Demo
- (void)functionCompletion:(void(^)(NSString *))completion {
    if (completion) {
        //灵活 异步 传值
        completion(@"调用完成了");
    }
}

使用:

    //把完成的结果传过来使用
    [self functionCompletion:^(NSString *word) {
        NSLog(@"%@",word);
    }];

类似这种应用很多吧,在网络请求用到的最多吧。

函数式编程方法封装: 比如UIButton addtarget。 Button和方法实现分开的。 这时候可以用函数式编程,将定义button和方法放在一起,用Block回调。