iOS开发-Block使用及循环引用的解决

Block是一种比较特殊的数据类型。它可以保存一段代码,在合适的时候取出来调用。

◦   我们可以把Block当做Objective-C的匿名函数。Block允许开发者在两个对象之间将任意的语句当做数据进行传递,往往这要比引用定义在别处的函数直观。另外,block的实现具有封闭性(closure),而又能够很容易获取上下文的相关状态信息。

◦   block是代码块,其本质和变量类似。不同的是代码块存储的数据是一个函数体。使用Block,就可以像其他标准函数一样,传入参数,并得到返回值。

  block的格式:

     a:Block的返回值类型,可以为空(void);

     b:Block对象名称,可以理解为变量名;

     ^:块的语法标记,声明b为一个Block对象; 

     c:第一个参数类型

     d:第二个参数类型

     name1,name2:参数名;

{}:Block代码块的主题部分。

Block使用场景,可以在两个界面的传值,也可以对代码封装作为参数的传递等。用过GCD就知道Block的精妙之处。

Block的修饰

ARC情况下

1.如果用copy修饰Block,该Block就会存储在堆空间。则会对Block的内部对象进行强引用,导致循环引用。内存无法释放。

解决方法:

新建一个指针(__weaktypeof(Target) weakTarget = Target )指向Block代码块里的对象,然后用weakTarget进行操作。就可以解决循环引用问题。

2.如果用weak修饰Block,该Block就会存放在栈空间。不会出现循环引用问题。

MRC情况下

copy修饰后,如果要在Block内部使用对象,则需要进行(__block typeof(Target) blockTarget =Target )处理。在Block里面用blockTarget进行操作。

Block结合typedef使用

自己定义一个Block类型,用定义的类型去创建Block,更加简单便捷。

这里举例一个Block回调修改上一下界面的背景颜色。ViewController1 控制器1ViewController2 控制器2,控制器1跳转到控制器2,然后在控制器2触发事件回调修改控制器1的背景颜色为红色。

ViewController2的实现

#import <UIKit/UIKit.h>

@interfaceViewController2 : UIViewController

/**

 *  定义了一个changeColorBlock。这个changeColor必须带一个参数,这个参数的类型必须为id类型的

 *  无返回值

 *  @param id

 */

typedefvoid(^changeColor)(id);

/**

 *  用上面定义的changeColor声明一个Block,声明的这个Block必须遵守声明的要求。

 */

@property (nonatomic, copy) changeColorbackgroundColor;

@end

-(void)touchesBegan:(NSSet<UITouch *> *)toucheswithEvent:(UIEvent *)event{

    //声明一个颜色

    UIColor *color = [UIColor redColor];

    //用刚刚声明的那个Block去回调修改上一界面的背景色

    self.backgroundColor(color);

}

ViewController1的实现

-(void)touchesBegan:(NSSet<UITouch *> *)toucheswithEvent:(UIEvent *)event{

    ViewController2*vc =[[ViewController2 alloc]init];

    // 回调修改颜色

   vc.backgroundColor = ^(UIColor *color){

        self.view.backgroundColor = color;

    };

    [self.navigationController pushViewController:vcanimated:YES];

}

__block关键字的使用

◦   在Block的代码块里,是不能修改在外面定义的变量,并且在给block赋值的时候,已经对代码块里的变量做了值的拷贝(只读不可修改)。

           
int x = 5;

               int (^block4)(int) =^(int y) {

                   int z =x + y;

                   returnz;

               };

                           NSLog(@"%d,%d",x+=5,block4(5));


打印的值是10,10;

                       分析:变量x在Block外定义的,在Block代码块编译的时候,取的x的值为之前的5(不可修改)。因此即使执行x += 5的使x的值变为10,但Block代码块里的x依然是5,所以block(5)的值为5+5=10。

◦   在变量前添加__block关键字进行修饰后,此变量在Block代码块里的就是可更改的(可读可写),执行代码时取变量最新的值。

           
__block int x = 5;

               int (^block4)(int) =^(int y) {

                   int z =x + y;

                   returnz;

               };

    NSLog(@"%d,%d",x+=5,block4(5));


打印的值是10,15;

 

当一个对象中的block块中的访问自己的属性会不会造成循环引用?

Block内部使用外部的一个对象,如果外部对象是强引用那么内部会自动生成一个强引用,引用着外部对象。如果外部对象是弱引用那么内部会自动生成一个弱引用,引用着外部对象。

在ARC下,只加一个__weak关键词就可以

在非ARC下,只加一个__block关键词就可以

去禁止blockself进行强引用或者强制增加引用计数。

若产生警告,weak变量被release掉,block代码块未执行,则

1)ARC环境下:ARC环境下可以通过使用_weak声明一个代替self的新变量代替原先的self,我们可以命名为weakSelf。通过这种方式告诉block,不要在block内部对self进行强制strong引用:(如果要兼容ios4.3,则用__unsafe_unretained代替__weak,不过目前基本不需考虑这么low的版本)

1          self.arr= @[@111, @222, @333];

2         __weak typeof(self) weakSelf=self;

3         self.block= ^(NSString *name){

4             NSLog(@"arr:%@", weakSelf.arr); };

2)MRC环境下:解决方式与上述基本一致,只不过将__weak关键字换成__block即可,这样的意思是告诉block:小子,不要在内部对self进行retain了!

http://www.jianshu.com/p/17872da184fb

http://www.cnblogs.com/laoNanHai/p/5537037.html

http://www.cnblogs.com/wengzilin/p/4347974.html

http://blog.csdn.net/fengsh998/article/details/38090205


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值