Block总结

#pragma mark - block的基本使用 只有调用block才会实现block中的代码

传入方声明block调用block,接收方实现block对传过来的值进行使用

#warining 1.声明block  2.调用block 3.实现block

一,Block的声明调用和实现

@implementation RootViewController


- (void)viewDidLoad {

    [super viewDidLoad];

     

    //声明一个名字为blockNameblock变量

    //-(void)funcName:(BOOL)value

    

    void(^blockName)(BOOL value,NSString *str); (1.声明Block这句话blockName是名字,其余的是类型)

   

    blockName = ^(BOOL va1,NSString * str1){     (3.实现block)

        NSLog(@"%d,%@",va1,str1);

    };

    //也可以把这一步和上一步合起来写,就是声明并且实现

    void(^blockName)(BOOL value,NSString *str) = ^(BOOL va1,NSString * str1){    

        NSLog(@"%d,%@",va1,str1);

    };


    blockName(YES,@"调用block");                   (2.调用block)

    //例如,声明一个带返回值的block,并且实现  之后调用block

    __unsafe_unretained RootViewController *rvc =self;

    NSString *(^block2)(UIColor * color) =^(UIColor * colorValue){

        

        rvc.view.backgroundColor = colorValue;

        return@"用来返回的字符串";

    };

    NSString *str = block2([UIColor greenColor]);

    NSLog(@"block返回的字符串====%@",str);

    

//定义block的三种方式,也就是实现block

 // block定义:三种方式 = ^(参数){};

    // 第一种

    void(^block1)() = ^{

        NSLog(@"调用了block1");

    };

    

    //第二种如果没有参数,参数可以隐藏,如果有参数,定义的时候,必须要写参数,而且必须要有参数变量名

    void(^block2)(int) = ^(int a){

        

    };

    

    //第三种 block返回可以省略,不管有没有返回值,都可以省略

    int(^block3)() = ^int{

        return 3;

    };

    //所以下面这样写也可以

//    int(^block3)() = ^{

//        return 3;

//    };

//  


二,Block在实际开发中的使用

1.把block定义为属性保存代码

@interface ViewController ()

// block怎么声明,就如何定义成属性

@property (nonatomic,strong)void(^block)();

@end


@implementation ViewController

// 1.在一个方法中定义,在另外一个方法调用

// 2.在一个类中定义,在另外一个类中调用


- (void)viewDidLoad {

    [super viewDidLoad];

    // Do any additional setup after loading the view, typically from a nib.

    // void(^)()

    void(^block)() = ^{

        NSLog(@"调用block");

    };

    

    _block = block;

    

}


- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event

{

    // block调用:就去寻找保存代码,直接调用  block有值得时候才待用

       if (_block){

    _block();

  }

}


2.block传值

//传值得根本就是只要拿到对方就能给对方传值,正向传值是这样的,反向传值也是(代理就是拿到他的代理属性,也相当于拿到对方的值)

SecodViewController  里面的代码

@property (nonatomic, copy)void(^block)(NSString *text);


//2.SecodViewController要传递文字,它是需要声明block的一方

//3.SecodViewController它声明,它调用 (这样才能传过去一个数,才叫反向传值)

//4.声明一个属性,指向要调用的block


/*

 1.驱动方声明一个block属性 驱动方调用block,执行block中得代码

 2.被动方要具体实现block<驱动的block属性应该指向被动方实现的block>

 

 */

if (_block) {

    

    _block(textField.text);

}


FirstViewController 里面的代码

//下面这代码在第一个控制器里面

//1.实现显示文字的功能,也就是它需要完成block的实现部分


SecodViewController *svc = [[SecodViewController alloc]init];


UILabel *label = (id)[self.view viewWithTag:10];


void(^aBlock)(NSString *text) = ^(NSString *text){

    label.text = text;

};

//声明的block指向实现的block

svc.block = aBlock;











    

3.block变量传递和内存管理

   // 如果block引用的是局部变量,Block是值传递  这时候如果是MRC就放在栈里面 ARC就放在堆里面

   // 如果block引用的是静态变量,全局变量,__block修饰的变量,都是指针传递  这时候block放在全局区



//block是个对象,苹果说的  

MRC的block内存管理:block如果没引用外部局部变量就是放在全局区,如果block引用外部的局部变量就会放在栈里面,因为mrc中没有强指针和弱指针,都是基本数据类型,基本数据类型都是放在栈里面去管理的


- 需要注意防止循环引用,使用__weak关键词修饰

void test5();


int main(int argc,constchar * argv[])

{

    test5();

    return0;

}


int num = 10;

void test5()

{

    void (^block)() = ^{

        // block内部能够一直引用全局变量  这时候的block放在全局区

        NSLog(@"----num=%d", num);

    };

    

    num = 20;

    

    block();

}


void test4()

{

    staticint age =10;

    void (^block)() = ^{

        // block内部能够一直引用被static修饰的变量  因为被static修饰的变量生命周期变了   这时候的block放在全局区

        NSLog(@"----age=%d", age);

    };

    

    age = 20;

    

    block();

}


void test3()

{

    __blockint age =10;

    void (^block)() = ^{

        // block内部能够一直引用被__block修饰的变量  mrc这时候的block放在栈里面

        

        NSLog(@"----age=%d", age);

    };

    

    age = 20;

    

    block();

}


void test2()

{

    int age =10;  //mrc的这时候的block也是放在栈里面

    void (^block)() = ^{

        // 普通的局部变量,block内部只会引用它初始的值(block定义那一刻),不能跟踪它的改变

        //因为block不知道这个变量什么时候被销毁,所以直接把变量的值放到那个位置,不管以后变量的死活了,但是全局变量,被static修饰的变量,被_block修饰的变量可以一直引用,就是可以跟踪变量的变化

        NSLog(@"----age=%d", age);

    };

    

    age = 20;

    

    block();

//这里面age的值还是10,不是20

}


void test()

{

    int age =10;

    void (^block)() = ^{

        // ----age=10

        NSLog(@"----age=%d", age);

    };

    block();

}


//block内存管理

/*

    block是不是一个对象?是一个对象

    如何判断当前文件是MRC,还是ARC

    1.dealloc 能否调用super,只有MRC才能调用super

    2.能否使用retain,release.如果能用就是MRC

 

    ARC管理原则:只要一个对象没有被强指针修饰就会被销毁,默认局部变量对象都是强指针,存放到堆里面

 

    MRC了解开发常识:1.MRC没有strong,weak,局部变量对象就是相当于基本数据类型

                  2.MRC给成员属性赋值,一定要使用set方法,不能直接访问下划线成员属性赋值   因为mrcset方法里面有retainrelease操作,不然会造成内存泄漏

 //- (void)setName:(NSString *)name

 //{

 //    if (name != _name) {

 //        [_name release];

 //        _name = [name retain];

 //    }

 //}


 

    MRC:管理block

            总结:只要block没有引用外部局部变量,block放在全局区

            只要Block引用外部局部变量,block放在栈里面.

            block只能使用copy,不能使用retain,使用retain,block还是在栈里面,这时候我们就没法访问block,访问栈里面的block会坏内存访问错误

 

    ARC:管理block

        只要block引用外部局部变量,block放在堆里面

        block使用strong.最好不要使用copy

总结:block如果没引用外部的局部变量就是放在全局区.如果引用了外部的局部变量,如果是MRC就放在栈里面,如果是ARC就放在堆里面  MRC使用copy ARC使用strong,因为用用weak这里的block局部变量就会被销毁,也不能用copy,因为我们只是赋值,没必要做一些copy操作

 

 */


4.block循环引用

复习modal 和push

当present或则push出来一个控制器,再调用这个控制器的dismiss和pop方法的时候这个控制器就会被销毁,但是dismiss(内部就是把self.presentViewController指针清除)和pop之前控制器不会被销毁

modal出来的控制器不会被销毁时因为这个控制器被self.presentViewController强引用着,所以modal控制器创建代码之后不会立马被销毁

 // block造成循环利用:Block会对里面所有强指针变量都强引用一次

    //这样防止循环引用,把里面的强指针变量辩称跟弱指针

    __weak typeof(self) weakSelf = self;



5.block当做参数

#import <Foundation/Foundation.h>

@interface CacultorManager : NSObject

@property (nonatomic, assign) NSInteger result;

// 计算

- (void)cacultor:(NSInteger(^)(NSInteger result))cacultorBlock;

@end

@implementation CacultorManager

- (void)cacultor:(NSInteger (^)(NSInteger))cacultorBlock

{

    if (cacultorBlock) {

      _result =  cacultorBlock(_result);

    }

}


@end


#import "ViewController.h"

#import "CacultorManager.h"

// 怎么区分参数是block,就看有没有^,只要有^.block当做参数

// block当做参数,并不是马上就调用Block,什么时候调用,由方法内部决定

// 什么时候需要把block当做参数去使用:做的事情由外界决定,但是什么时候做由内部决定

/*

    需求:封装一个计算器,提供一个计算方法,怎么计算由外界决定,什么时候计算由内部决定.

 */

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {

    [super viewDidLoad];

    // 创建计算器管理者

    CacultorManager *mgr = [[CacultorManager alloc] init];

    [mgr cacultor:^(NSInteger result){

        result += 5;

        result += 6;

        result *= 2;

        return result;

    }];

    NSLog(@"%ld",mgr.result);

    

}


6.block当返回值

#import <Foundation/Foundation.h>

@interface CalculatorManager : NSObject

@property (nonatomic, assign) int result;

//参数是int 返回值是自己

- (CalculatorManager *(^)(int))add;

@end


#import "CalculatorManager.h"

@implementation CalculatorManager

- (CalculatorManager *(^)(int))add

{

    //实现block的部分

    return ^(int value){

        _result += value;

        return self;

    };

}


#import "ViewController.h"

#import "CalculatorManager.h"

@interface ViewController ()

@end

@implementation ViewController

/*

    链式编程思想:把所有的语句用.号连接起来,好处:可读性非常好

 */

/*

    需求:封装一个计算器,提供一个加号方法

 */

- (void)viewDidLoad {

    [super viewDidLoad];

    CalculatorManager *mgr = [[CalculatorManager alloc] init];

    // + 5

    // mgr.add(5).add(5).add(5).add(5).add(5).add(5)

    // mgr.add(5)

//    [[[[[mgr add:5] add:5] add:5] add:6] add:7];

    mgr.add(5).add(5).add(5).add(5); //返回值都是block,这里是调用block

    NSLog(@"%d",mgr.result);

//    [mgr add:5];

//    [mgr add:5];

//    [mgr add:5];

//    [mgr add:5];


}



@end





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值