美文网首页
Block学习笔记

Block学习笔记

作者: 冷武橘 | 来源:发表于2020-04-19 21:32 被阅读0次

    Block的初始化

    block是一种特殊的数据类型,和Int,double,float....一样,可定义变量、作为参数、作为返回值。block可以用来保存一段代码,在恰当的时间再取出来调用,一般在动画、多线程、集合遍历、网络请求回掉中都经常见的到。

    • block的声明和定义
        1;               //整形
        2.1;             //浮点型
        @"2";            //字符串
        ^{
          NSLog(@"block是一种特殊的数据类型");
        };                //blockl类型;
    

    block是一种特殊的数据类型,书写形式也就是在大括号前加上一个^,而大括号里可以保存代码段。

       int a;               //整形变量声明
       float b;             //浮点型变量声明
       NSString *str ;            //变量声明
      void(^myblock)();    //block类型变量声明
    
        a=12;
        b= 11.2;
        str=@"123";
        myblock=^(){
          NSLog(@"block类型的变量myblock赋值");
        };
    int c=12;
    void(^hltblock)=^{
    NSLog(@"block变量声明的同时并赋值");
    };
    

    在定义和初始化block时,我们要时刻记住block也是一种特殊的数据类型,其初始化方式和其他数据类型一样。
    1.有参数的block

       void(^hblock)(int,NSString*)=^(int a,NSString*b){
            NSLog(@"%d %@",a,b);
        };
        hblock(2,@"qqq");
    

    2.无参数的block

      void(^hblock)()=^(){
            NSLog(@"无参数的block");
        };
      void(^bblock)()=^{
            NSLog(@"无参数的block,小括号可以省略");
        };
    

    3.有返回值的block

     int(^block3)() = ^int{
            return 3;
        };
     int(^block5)() = ^{
          NSLog(@"block返回可以省略,不管有没有返回值,都可以省略
    ");
            return 3;
        };
        NSLog(@"%d",block5());  
    
       // block快捷方式 inline
      <#returnType#>(^<#blockName#>)(<#parameterTypes#>) = ^(<#parameters#>) {
     <#statements#>
      };
    

    Block内部访问外部变量

        c=666;
        int a =10;
        __block int b=11;
        void(^lwjblock)()=^(){
            NSLog(@"%d",a);//默认情况下,block内部可以访问外面的变量
            //a = 13;//默认情况下,block内部不能修改外面的局部变量
            b=14;//给局部变量加上__block关键字,就可以修改局部变量了
            NSLog(@"%d",b);
            c=123;//全局变量可以修改
            NSLog(@"%d",c);
        };
        lwjblock();
    
    

    Block内部访问外部变量

    • 值传递
    //如果是局部变量,Block是值传递
    int a = 3;
    void(^block)() = ^{
      NSLog(@"%d",a);
    };
    a = 5;
    block();//block打印出的是3,是值传递
    //block中使用的外面变量的值是拷贝过来的即值拷贝,所以在调用之前修改外界变量的值,不会影响到block中拷贝的值.
    
    • 指针传递
    // 如果是静态变量,全局变量,__block修饰的变量,block都是指针传递
    __block int a = 3;
    void(^block)() = ^{
     NSLog(@"%d",a);
    };
    a = 5;
    block();//这里调用block打印出的是5,是指针传递,可以直接影响变量的值
    

    Block实战应用01-(保存代码)

    应用场景描述:点击不同的cell跳转到不同的界面

    #import <Foundation/Foundation.h>
    #import <UIKit/UIKit.h>
    @interface Settingitem : NSObject
    /** 图片 */
    @property (nonatomic, strong) UIImage *icon;
    
    /** 标题 */
    @property (nonatomic, copy) NSString *title;
    
    /** 点击这一行要做的事情 */
    @property (nonatomic, copy) void(^operation)(NSIndexPath *indexPath);
    
    + (instancetype)itemWithIcon:(UIImage *)icon title:(NSString *)title;
    #import "Settingitem.h"
    
    @implementation Settingitem
    
    + (instancetype)itemWithIcon:(UIImage *)icon title:(NSString *)title{
        Settingitem *item = [[self alloc] init];
        
        item.icon = icon;
        
        item.title = title;
        
        return item;
    }
    @end
    
    
    
    #import <UIKit/UIKit.h>
    
    @interface SettingController : UIViewController
    
    @end
    #import "SettingController.h"
    #import "Settingitem.h"
    @interface SettingController ()<UITableViewDelegate,UITableViewDataSource>
    
    /** 数组总数 */
    @property (nonatomic, strong) NSMutableArray *groups;
    @end
    
    @implementation SettingController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        self.view.backgroundColor=[UIColor whiteColor];
        self.title=@"设置";
        UITableView *tableview=[[UITableView alloc]initWithFrame:self.view.bounds style: UITableViewStylePlain];
        tableview.delegate=self;
        tableview.dataSource=self;
        [self.view addSubview:tableview];
        _groups = [NSMutableArray array];
        Settingitem *item1 = [Settingitem itemWithIcon:[UIImage imageNamed:@"RedeemCode"] title:@"使用税换码"];
        item1.operation = ^(NSIndexPath *indexpath){
            NSLog(@"使用税换码");
        };
        Settingitem *item2 = [Settingitem itemWithIcon:[UIImage imageNamed:@"MorePush"] title:@"推送和提醒"];
       //保存代码,保存要做的事
        item2.operation = ^(NSIndexPath *indexpath){
            NSLog(@"推送和提醒");
        };
        Settingitem *item3 = [Settingitem itemWithIcon:[UIImage imageNamed:@"handShake"] title:@"使用摇一摇机选"];
        item3.operation = ^(NSIndexPath *indexpath){
            NSLog(@"使用摇一摇机选");
        };
        [self.groups addObject:item1];
        [self.groups addObject:item2];
        [self.groups addObject:item3];
    }
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
        Settingitem *item =  self.groups[indexPath.row];
        if (item.operation) {
            item.operation(indexPath);
        }
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    
        return self.groups.count;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        static NSString *ID = @"cell";
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
        if (cell == nil) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
            cell.accessoryType=UITableViewCellAccessoryDisclosureIndicator;
        }
        Settingitem *item =  self.groups[indexPath.row];
        cell.imageView.image = item.icon;
        cell.textLabel.text = item.title;
        return cell;
    }
    @end
    

    Block实战应用02-(逆向传值)

    #import "ViewController.h"
    #import "ModalViewController.h"
    @interface ViewController ()
    @end
    @implementation ViewController
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
        ModalViewController *modalVc = [[ModalViewController alloc] init];
        modalVc.view.backgroundColor = [UIColor brownColor];
    
        modalVc.block = ^(NSString *value) {
          
            NSLog(@"%@",value);
        };
        
        // 跳转
        [self presentViewController:modalVc animated:YES completion:nil];
    }
    @end
    
    #import <UIKit/UIKit.h>
    @interface ModalViewController : UIViewController
    //定义个block属性,以此为媒介进行传值
    @property (nonatomic, strong) void(^block)(NSString *value);
    @end
    #import "ModalViewController.h"
    @interface ModalViewController ()
    @end
    @implementation ModalViewController
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
        // 传值给ViewController
        if (_block) {
            _block(@"123");
        }
    }
    @end
    

    Block实战应用03-(作为参数使用)

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

    #import <Foundation/Foundation.h>
    @interface CacultorManager : NSObject
    @property (nonatomic, assign) NSInteger result;
    // 计算
    - (void)cacultor:(NSInteger(^)(NSInteger result))cacultorBlock;
    @end
    #import "CacultorManager.h"
    @implementation CacultorManager
    - (void)cacultor:(NSInteger (^)(NSInteger))cacultorBlock
    {
        if (cacultorBlock) {
          _result =  cacultorBlock(_result);
        }
    }
    @end
    
    #import "ViewController.h"
    #import "CacultorManager.h"
    @interface ViewController ()
    @end
    @implementation ViewController
    - (void)viewDidLoad {
        [super viewDidLoad];
        // 把block当做参数,并不是马上就调用Block,什么时候调用,由方法内部决定
        // 什么时候需要把block当做参数去使用:做的事情由外界决定,但是什么时候做由内部决定.
        // 创建计算器管理者
        CacultorManager *mgr = [[CacultorManager alloc] init];
        [mgr cacultor:^(NSInteger result){
            result += 5;
            result += 6;
            result *= 2;
            return result;
        }];
    }
    @end
    

    封装一个网络请求工具类

    #import <Foundation/Foundation.h>
    #import "AFNetworking.h"
    @interface HttpTool : NSObject
    /**
     *  发送一个GET请求
     *
     *  @param url     请求路径
     *  @param params  请求参数
     *  @param success 请求成功后的回调(请将请求成功后想做的事情写到这个block中)
     *  @param failure 请求失败后的回调(请将请求失败后想做的事情写到这个block中)
     */
    + (void)get:(NSString *)url params:(NSDictionary *)params success:(void(^)(id responseObj))success failure:(void(^)(NSError *error))failure;
    
    /**
     *  发送一个POST请求
     *
     *  @param url     请求路径
     *  @param params  请求参数
     *  @param success 请求成功后的回调(请将请求成功后想做的事情写到这个block中)
     *  @param failure 请求失败后的回调(请将请求失败后想做的事情写到这个block中)
     */
    + (NSURLSessionDataTask *)post:(NSString *)url params:(NSDictionary *)params success:(void(^)(id responseObj))success failure:(void(^)(NSError *error))failure;
    @end
    
    #import "HttpTool.h"
    @implementation HttpTool
    +(void)get:(NSString *)url params:(NSDictionary *)params success:(void (^)(id))success failure:(void (^)(NSError *))failure
    {
        //1.获得请求管理者
        AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];
        
        //2.发送Get请求
        [mgr GET:url parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            if (success) {
                success(responseObject);
            }
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            if (failure) {
                failure(error);
            }
        }];
    }
    
    +(NSURLSessionDataTask *)post:(NSString *)url params:(NSDictionary *)params success:(void (^)(id))success failure:(void (^)(NSError *))failure
    {
        //1.获得请求管理者
        AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];
       NSURLSessionDataTask *dataTask = [mgr POST:url parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
           if (success) {
               success(responseObject);
           }
       } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
           
           if (failure) {
               failure(error);
           }
       }];
        return dataTask;
    }
    @end
    

    解决block循环引用

    #import "Secviewcontroller.h"
    #import "Person.h"
    @interface Secviewcontroller (){
        Person * _person;
    }
    @property(nonatomic,copy)void(^block)();
    @property(nonatomic,strong)NSString *name;
    
    @end
    
    @implementation Secviewcontroller
    /*
     循环引用:我引用你,你也引用,就会造成循环引用,双方都不会被销毁,导致内存泄露问题
     
    block造成循环利用:Block会对里面所有强指针变量都强引用一次 
     
     解决循环引用: 创建一个弱指针,如果外部对象是弱引用那么内部会自动生成一个弱引用,引用着外部对象。关键字:__weak
     
     */
    - (void)viewDidLoad {
        [super viewDidLoad];
           self.view.backgroundColor=[UIColor whiteColor];
        [self test2];
    }
    //解决循环引用
    - (void)test1{
        /*理解self:在当前指的是一个 Secviewcontroller对象,
         即 :Secviewcontroller *weakself=self;
         默认指针变量都是强指针,即
         __strong Secviewcontroller *weakself=self;
         为了避免循环引用,我们需要把__strong指针变成弱指针,于是我们需要这样就接受拿到self, 即
         __weak Secviewcontroller *weakself=self;
         */
        
        __weak Secviewcontroller *weakself=self;
    
       self.block=^(){
            NSLog(@"%@",weakself.name);
        };
    
    }
    - (void)test2{
     __strong Person *p = [[Person alloc] init];
      
        __weak  Person *weakperson=p;
    
       p.personblock=^(){
         NSLog(@"%@",weakperson.name);
      };
    }
    
    //typeof(x) 函数动态根据x判断x的真实类型
    - (void)commara{
        int a = 10;
        typeof(1) b =30;
        NSLog(@"a %d b %d",a, b);
        
        __weak typeof(self)weakself = self;
        //typeof(self)相当于Secviewcontroller *
        
        Person *p = [[Person alloc] init];
        __weak typeof(p)weakperson = p;
        NSLog(@"%@",[weakperson class]);
        //typeof(self)相当于Person *
    }
    - (void)test3{
       Person *p = [[Person alloc] init];
        __weak  typeof(p)weakperson = p;
        
        p.personblock=^(){
            NSLog(@"%@",weakperson.name);
        };
        __weak typeof(self)weakself = self;
        self.block= ^(){
            NSLog(@"%@",weakself);
        };
        
    }
    //控制器只有被销毁时,才会被调用。(即循环引用的情况下,不会被调用)
    -(void)dealloc{
        NSLog(@"被释放销毁了");
    }
    @end
    

    相关文章

      网友评论

          本文标题:Block学习笔记

          本文链接:https://www.haomeiwen.com/subject/njoibhtx.html