Osheep

时光不回头,当下最重要。

IOS开发-block分析

block的定义

// 无参无返回
void(^block)();
// 无参有返回
int(^block1)();
// 有参有返回
int(^block1)(int number);

也可以直接打入inline来自动生成block格式

<#returnType#>(^<#blockName#>)(<#parameterTypes#>) = ^(<#parameters#>) {
        <#statements#>
    };

block的循环引用

  • 如果要在block中直接使用外部强指针会发生错误,使用以下代码在block外部实现可以解决
__weak typeof(self) weakSelf = self;
  • 但是如果在block内部使用延时操作还使用弱指针的话会取不到该弱指针,需要在block内部再将弱指针强引用一下
__strong typeof(self) strongSelf = weakSelf;

block的内存管理

  • 无论当前环境是ARC还是MRC,只要block没有访问外部变量,block始终在全局区
  • MRC情况下
    1.block如果访问外部变量,block在栈里
    2.不能对block使用retain,否则不能保存在堆里
    3.只有使用copy,才能放到堆里
  • ARC情况下
    1.block如果访问外部变量,block在堆里
    2.block可以使用copy和strong,并且block是一个对象

通过block来传值

  • 在控制器间传值可以使用代理或者block,使用block相对来说简洁

在前一个控制器的touchesBegan:方法内实现如下代码

    ModalViewController *modalVc = [[ModalViewController alloc] init];

    modalVc.valueBlcok = ^(NSString *str){

        NSLog(@"ViewController拿到%@",str);
    };

    [self presentViewController:modalVc animated:YES completion:nil];

ModalViewController控制器的.h文件中声明一个block属性 @property (nonatomic ,strong) void(^valueBlcok)(NSString *str);

并在.m文件中实现方法

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    // 传值:调用block
    if (_valueBlcok) {
        _valueBlcok(@"123");
    }
}

这样在ModalViewController回到上一个控制器的时候,上一个控制器的label就能显示ModalViewController传过来的字符串

block作为一个参数使用

新建一个类,在.h文件中声明一个方法- (void)calculator:(int(^)(int result))block;

并在.m文件中实现该方法

- (void)calculator:(int (^)(int))block
{
    self.result = block(self.result);
}

在其他类中调用该方法

    CalculatorManager *mgr = [[CalculatorManager alloc] init];
    [mgr calculator:^(int result){
        result += 5;
        return result;
    }];

block作为返回值使用

masonry框架中我们可以看到如下用法make.top.equalTo(superview.mas_top).with.offset(padding.top); 这个方法实现就是将block作为返回值来使用

来分析一下这段代码
其实可以将这段代码看成make.top,make.equalTo,make.with,make.offset,所以可以得出一个结论是make.top返回了一个make,才能实现make.top.equalTo

那来模仿一下这种功能的实现“`
新建一个类,在.h文件中声明一个方法- (CalculatorManager *(^)(int a))add;

.m文件中实现方法

- (CalculatorManager * (^)(int a))add
{
    return ^(int a){
        _result += a;
        return self;
    };
}

这样就可以在别的类中实现上面代码的用法

mgr.add(1).add(2).add(3);

block的变量传递

  • 如果block访问的外部变量是局部变量,那么就是值传递,外界改了,不会影响里面
  • 如果block访问的外部变量是__block或者static修饰,或者是全局变量,那么就是指针传递,block里面的值和外界同一个变量,外界改变,里面也会改变

验证一下是不是这样
通过Clang来将main.m文件编译为C++
在终端输入如下命令clang -rewrite-objc main.m

void(*block)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_a_0 *)&a, 570425344));
void(*block)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a));

可以看到在编译后的代码最后可以发现被__block修饰过得变量使用的是&a,而局部变量是a

还在学习中,有错误请指出,谢谢!!

点赞