Block总结

    xiaoxiao2021-03-25  114

    #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

    转载请注明原文地址: https://ju.6miu.com/read-19293.html

    最新回复(0)