iOS block的基本使用

  • block作用:保存一段代码
    1.block声明
    2.block定义
    4.block类型
    5.block调用
    //block的声明  返回值 (^block的名字)(参数)
    void (^myblock)();
    
    /*定义  = ^(参数){} */
    //1.没有参数, 没有返回值
    void (^block1)() = ^{ //没有参数在定义的时候可以省略
        NSLog(@"调用了block1");
    };
    // 2 如果没有参数,参数可以隐藏,如果有参数,定义的时候,必须要写参数,而且必须要有参数变量名
    void (^block2) (int) = ^(int a)    //有参数 没有返回值的

    {
        
    };
    //3 第三种 block返回可以省略,不管有没有返回值,都可以省略
    int (^block3)() = ^int
    {
        return 3;
    };
    int (^block4)() = ^
    {
        return 4;
    };
    
    
    //block的调用
    block1();
    
    // block快捷方式 inline
//    <#returnType#>(^<#blockName#>)(<#parameterTypes#>) = ^(<#parameters#>) {
//        <#statements#>
//    };

开发中的使用场景

  • 1保存代码

    • 在一个方法中定义在另一个方法中调用
//定义别名
typedef void(^BlockTyoe)();

@interface ViewController ()

@property (nonatomic, strong)  BlockTyoe block1;

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

// 1.在一个方法中定义,在另外一个方法调用
// 2.在一个类中定义,在另外一个类中调用
/*
 1.tableView展示3个cell,打电话,发短信,发邮件
 
 */
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    void (^block) () = ^
    {
        NSLog(@"在这里保存了一份需要执行的代码");
    };
    _block = block;
    
}


- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    self.block();//执行
//    UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:[[MyToolTVC alloc]init]];
//    [self presentViewController:nav animated:YES completion:nil];
    
}


- (void)viewDidLoad {
    [super viewDidLoad];
    
    _items = [NSMutableArray array];
    
    
    
    MyToolItem *item1 = [MyToolItem itemWithTitle:@"打电话"];
    item1.clickAciton = ^
    {
        NSLog(@"我要打电话");
    };
    [self.items addObject:item1];
    MyToolItem *item2 = [MyToolItem itemWithTitle:@"发短信"];
    item2.clickAciton = ^
    {
        NSLog(@"我要打短信");
    };
    [self.items addObject:item2];

    MyToolItem *item3 = [MyToolItem itemWithTitle:@"发邮件"];
    item3.clickAciton = ^
    {
        NSLog(@"我要邮件");
    };
    [self.items addObject:item3];


    
}

#pragma mark - Table view data source

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.items.count;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *const toolCellId = @"toolCellId";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:toolCellId ];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:toolCellId];
    }
    
    MyToolItem *item = self.items[indexPath.row] ;
    cell.textLabel.text = item.toolTitle;
    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    MyToolItem *item = self.items[indexPath.row] ;
    item.clickAciton();
}


  • 2传值

    • 传值:1.只要能拿到对方就能传值
      顺传:给需要传值的对象,直接定义属性就能传值
      逆传:用代理,block,就是利用block去代替代理
  • 代理传值

#import "ViewController.h"
#import "ModelViewViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}
/*
 传值:1.只要能拿到对方就能传值
 顺传:给需要传值的对象,直接定义属性就能传值
 逆传:用代理,block,就是利用block去代替代理
 */
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    ModelViewViewController *modelVC = [[ModelViewViewController alloc] init];
    modelVC.delegate = self;
    
    modelVC.view.backgroundColor = [UIColor orangeColor];
    [self presentViewController:modelVC animated:YES completion:nil];
}

- (void)modelViewController:(ModelViewViewController *)vc senderMessage:(NSString *)message
{
    NSLog(@"收到了消息%@", message);
}
@end

@class ModelViewViewController;
@protocol ModelViewControllerDelegate 

- (void)modelViewController:(ModelViewViewController *)vc senderMessage:(NSString *)message;
@end

@interface ModelViewViewController : UIViewController

@property (nonatomic, weak)  id delegate;

@end


#import "ModelViewViewController.h"

@interface ModelViewViewController ()

@end

@implementation ModelViewViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (self.delegate && [self.delegate respondsToSelector:@selector(modelViewController:senderMessage:)]) {
        [self.delegate modelViewController:self senderMessage:@"12355"];
    }
}

@end

  • block传值
@interface ModelViewViewController : UIViewController

@property (nonatomic, weak)  id delegate;
@property (nonatomic, strong)  void(^sendValue)(NSString *);


@end

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (self.sendValue) {
        self.sendValue(@"你好呀 block");
    }
}



/*********ViewController.m*******/
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    ModelViewViewController *modelVC = [[ModelViewViewController alloc] init];
    modelVC.sendValue =^ (NSString *value)
    {
        NSLog(@"这是收到的%@", value);
    };
    modelVC.view.backgroundColor = [UIColor orangeColor];
    [self presentViewController:modelVC animated:YES completion:nil];
}

block的内存管理

  • mrc

  • block是不是一个对象?是一个对象
    如何判断当前文件是MRC,还是ARC
    1.dealloc 能否调用super,只有MRC才能调用super
    2.能否使用retain,release.如果能用就是MRC
    ARC管理原则:只要一个对象没有被强指针修饰就会被销毁,默认局部变量对象都是强指针,存放到堆里面
    MRC了解开发常识:1.MRC没有strong,weak,局部变量对象就是相当于基本数据类型
    2.MRC给成员属性赋值,一定要使用set方法,不能直接访问下划线成员属性赋值
    MRC:管理block
    总结:只要block没有引用外部局部变量,block放在全局区
    只要Block引用外部局部变量,block放在栈里面.
    block只能使用copy,不能使用retain,使用retain,block还是在栈里面

  • ARC:管理block

只要block引用外部局部变量,block放在堆里面
block使用strong.最好不要使用copy

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


@end
/*
 ARC:管理block
 只要block引用外部局部变量,block放在堆里面
 block使用strong.最好不要使用copy
 */
@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    __block int a = 3;
    void(^block)()= ^
    {
        NSLog(@"%d",3);
        a = 4;
    };
    self.block = block;
}

block的循环引用

  • 循环引用:我引用你,你也引用,就会造成循环引用,双方都不会被销毁,导致内存泄露问题
  • block造成循环利用:Block会对里面所有强指针变量都强引用一次

比如我们如果在block中直接引用self当控制器被diss Miss的时候我们发现 并没有执行销毁,这就出现了循环了引用,因为block会对当前的控制器进行强引用,解决方法,定义一个弱引用,


    NSLog(@"%@", self);
    __weak typeof (self) weakSelf = self;
     self.block= ^
    {
        NSLog(@"%d", weakSelf.age);
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        //    NSLog(@"引用了%@", strongSelf);
        });
    };
    
    self.block();
    
}
  • 弱引用可以实现我们的平时开发所用到的基本的功能,如果我们想在延迟的时候使用的话需要对weakself强引用一次防止他被销毁
    这样我们就要对他进行一次引用
 __weak typeof (self) weakSelf = self;
     self.block= ^
    {
        NSLog(@"%d", weakSelf.age);//如果block里面有延迟操作,可能你会照成 拿不到当前的控制器,比如 被dismiss掉了
     //如果我们想在延迟的时候使用的话需要对weakself强引用一次防止x他被销毁
        __strong typeof(weakSelf) strongSelf = weakSelf;
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//延迟执行的时候 被modal出的控制应景dismiss掉了,但是不会执行销毁
            NSLog(@"引用了%@", strongSelf);
        });
    };
    
    self.block();
    
  • 原理

viewController 通过present出modalController,这时候 viewController会有一个强指针,指向modal,然后block中有定义一个 __strong typeof(weakSelf) strongSelf = weakSelf;
这样block也有一个强指针指向了modal控制器,然后延迟的block中引用了strongSelf这样就对strongSelf这个局部变量有了强引用。保证了让他不销毁。当我们在执行dismiss的时候viewController指向modal的强指针去掉了, 当执行了延迟操作之后,系统会将这个延迟操作中的block中引用的强去掉指针。当延迟的操作的强指针去掉后,上一个block中的strongSelf就没有强指针引用了,所以也会被系统销毁。这样就没有强指针指向当前的modal对象了,这个时候他才会被系统销毁。


block变量传递

  • 如果是局部变量,Block是值传递
    如果是静态变量,全局变量,__block修饰的变量,block都是指针传递
- (void)viewDidLoad {
    [super viewDidLoad];
    int a = 3;
    
    self.block = ^
    {
        NSLog(@"%d", a);//3
    };

    a= 5;

}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    self.block();
}

block当参数使用

  • 怎么区分参数是block,就看有没有,只要有.把block当做参数
    把block当做参数,并不是马上就调用Block,什么时候调用,由方法内部决定。
    什么时候需要把block当做参数去使用:做的事情由外界决定,但是什么时候做由内部决定.
 CaculterViewController *cacultorVC = [[CaculterViewController alloc] init];
    [cacultorVC cacultor:^NSInteger(NSInteger result) {
        result +=2;
        result +=6;
        result *= 3;

        return result;
    }];
    NSLog(@"%ld", cacultorVC.result);


/ *******************/

#import "CaculterViewController.h"

@interface CaculterViewController ()

@end

@implementation CaculterViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}


- (void)cacultor:(NSInteger (^)(NSInteger))cacultorBlock
{
    
    if (cacultorBlock) {
        _result = cacultorBlock(_result);
    }
}


作为返回值

  • 链式编程思想:把所有的语句用.号连接起来,好处:可读性非常好
    当方法的返回值为block类型的时候,可以用.语法加()直接调用,最常见的就是masonry,d我们定约束的时候全部都使用的.
    make.center .equalTo(redView)
#import "ViewController.h"
#import "CaculterViewController.h"

@interface ViewController ()

@end

@implementation ViewController

/*
 需求:封装一个计算器,提供一个加号方法
 */
- (void)viewDidLoad {
    [super viewDidLoad];
 
    self.test();
    //上面的方法相当于
    void (^testB)() = self.test;
    testB();
    //当函数的返回值为block的时候可以用();就好比直接调用block,
    ^{
        NSLog(@"myanmetest");
    }();
    
    CaculterViewController *mgr = [[CaculterViewController alloc] init];
    mgr.add(3).add(5).add(8);
    NSLog(@"%d", mgr.result);
}

- (void (^)())test
{
    return ^{
        NSLog(@"调用返回的block");
        };
}


/***************************/
- (CaculterViewController * _Nonnull (^)(NSInteger))add
{
    
    return ^(NSInteger value){
        _result += value;
        return self;
    };
}


你可能感兴趣的:(iOS block的基本使用)