• Block的使用及循环引用的解决


      Block是一个很好用的东西,这篇文章主要来介绍:1.什么是Block?2.Block的使用?3.Block的循环引用问题及解决.

    1.什么是Block?

      说这个问题之前,我先来说一下闭包(Closure)。闭包就是一个函数,或者一个指向函数的指针,加上这个函数执行的非局部变量。说的通俗一点,就是闭包允许一个函数访问声明该函数运行上下文中的变量,甚至可以访问不同运行上文中的变量。

      Block实际上就是OC语言对闭包的实现。

      下面声明一个Block:

    1 int (^Sum)(int, int);

      首先,第一个int也就是该Block的返回值类型,也可以是其他的返回值类型,或者无返回值。“^”是Block的标识。第二以及第三个int,则是Block的参数类型,当然也可以无参数。

      下面的代码则是定义了一个Block,当执行Line5代码时,会输出“nihao”,也就是给Block传入的参数。

    1 void (^printBlock)(NSString *) = ^(NSString *str) {
    2     NSLog(@"%@", str);
    3 };
    4 
    5 printBlock(@"nihao");

    下面借鉴一张网上流传的图片总结一下Block的结构:

      需要说明的是,Block能够直接修改和访问全局变量,但是只能访问局部变量,如果想要在Block中修改局部变量,使用 __block 修饰即可。关于Block的基本介绍就是这么多了。有需要的tx可以留言,再做适当的更新。下面简单说说Block的使用。

    2.Block的使用

    2.1 使用Block在不同的页面进行传值

      页面传值有很多方式,比如:属性、单例、通知、代理,Block等。这里单说使用Block传值,其他几种以后再做补充。

      使用Block传值也有两种方式:Block属性和使用Block作为参数的方法。

    2.1.1 使用Block属性传值

      下面演示的是从B页面(后一个页面)传值到A页面(前一个页面)。

      首先在B页面中声明一个Block,通常为了使代码简洁,我一般会对Block进行重定义:

    typedef void (^PassVal)(NSString *text);

      接着,在B中声明一个Block属性:

    @property (nonatomic, copy) PassVal passVal;

      这里需要注意下,我使用了copy,实际上在ARC环境下,使用copy和strong都是可行的。我这里只是为了表明,使用Block时,实际上是把Block从栈区拷贝到了堆区。

      下面继续。我这里选择在B页面即将消失时,将值传出:

    1 - (void)viewWillDisappear:(BOOL)animated {
    2     if (self.passVal) {
    3         self.passVal(@"1234567898");
    4     }
    5 }

      我们可以看一下前面声明的Block是一个有参(string类型),无返回值。这里我给Block的参数是@"123456798"。通过上面的处理,B页面的操作已经完成了。下面进行A页面的操作:

    - (void)btnNextAction:(UIButton *)btnNext {
        BViewController *BVC = [[BViewController alloc] init];
        BVC.passVal = ^(NSString *text) {
            NSLog(@"%@",text);
        };
        [self.navigationController pushViewController:BVC animated:YES];
    }

      上面的代码演示了,在点击按钮即将push到B页面时,来实现Block。这样就可以在A页面中得到B页面的值,也就是text值。到此,Block属性传值结束。

    2.1.2 使用带有Block参数的方法传值

      这种方式和属性传值类似,下面做简单的示例:

    1 typedef void (^PassVal)(NSString *text);
    2 
    3 @interface SecondViewController : UIViewController
    4 
    5 @property (nonatomic, copy) PassVal passVal;
    6 
    7 - (void)returnText:(PassVal)block;
    8 
    9 @end

      首先在第二个页面同样需要声明Block属性,同时在第二个页面声明一个方法,方法的参数即是属性同样类型的Block。接着实现下面的方法:

    1 - (void)viewWillDisappear:(BOOL)animated {
    2     if (self.passVal) {
    3         self.passVal(@"1234567898");
    4     }
    5 }
    6 
    7 - (void)returnText:(PassVal)block {
    8     self.passVal = block;
    9 }  

      首先要做的还是先给Block的参数赋值,接着要实现声明的方法。接下来去第一个页面操作:

    1 - (void)btnNextAction:(UIButton *)btnNext {
    2     SecondViewController *secCtr = [[SecondViewController alloc] init];
    3     [secCtr returnText:^(NSString *text) {
    4         NSLog(@"%@",text);
    5     }];
    6     
    7     [self.navigationController pushViewController:secCtr animated:YES];
    8 }

      这样也可以实现传值。

      使用方法传值,猛一看觉得挺麻烦,但是实际上,使用方法调用的方式是很容易理解的。

      传值只是Block的简单应用,总体来说,Block和代理的使用时很类似的,可以互相参考着学习。

    3.Block的循环引用问题及解决.

      首先我们需要明确的是,一个对象的Block属性是使用copy来修饰,当Block被copy时,会对block中用到的对象产生强引用(ARC)或者引用计数加一(MRC)。当我们使用Block时,如果Block方法又引用了对象,如使用 self. 来引用对象的属性,这就会造成循环引用。其实如果产生了循环引用我们也不需要很担心,因为编译器会自动提醒,只需要在提醒的时候进行处理就可以了.一般在ARC下可以这么处理(仅作为示例用法):

        __weak typeof(self)weakSelf = self;
        [self.tableView addHeaderWithCallback:^{
            weakSelf.isDown = YES;
            weakSelf.page = 1;
            [weakSelf requestData];
        }];

    也就是说,把需要使用self的地方换成weakSelf即可.如果是MRC,只需要把上面代码的第一行更换为:

    __block typeof(self)weakSelf = self;

    以上仅作为各位使用的参考,如果有不到位的地方,欢迎各位留言指出,大家一起交流.

    转载请注明出处
  • 相关阅读:
    Java 线程池
    eclipse 创建Java web项目 Cannot change version of project facet Dynamic web module to xxx
    Maven maven-compiler-plugin 编译问题
    设计模式 单例模式
    Spring 配置文件注入
    Java HashMap、HashTable与ConCurrentHashMap
    Java Web ActiveMQ与WebService的异同
    Java Web 拦截器和过滤器的区别
    html2canvas 使用指南
    js动态改变setInterval的时间间隔
  • 原文地址:https://www.cnblogs.com/zzuliliu/p/5430649.html
Copyright © 2020-2023  润新知