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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Block Block底层原理实现 首先我们来看四个函数 造成这样的原因是:传值和传址。为什么说会有传值和传址,把...
    b485c88ab697阅读 12,364评论 0 41
  • 1、Block底层原理实现 首先我们来看四个函数 造成这样的原因是:传值和传址。为什么说会有传值和传址,把.m编译...
    iLees阅读 4,168评论 0 4
  • 前言 Blocks是C语言的扩充功能,而Apple 在OS X Snow Leopard 和 iOS 4中引入了这...
    小人不才阅读 9,136评论 0 23
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,359评论 19 139
  • 《Objective-C高级编程》这本书就讲了三个东西:自动引用计数、block、GCD,偏向于从原理上对这些内容...
    WeiHing阅读 13,325评论 10 69