美文网首页
Block相关

Block相关

作者: CoderLNHui | 来源:发表于2017-01-13 13:55 被阅读26次

Block基本使用

  • 1.1、block声明:
    返回值(^block变量名)(参数)

    void(^block)();

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

  • 第一种

    void(^block1)() = ^{

        NSLog(@"调用了block1");

    };
  • 第二种 如果没有参数,参数可以隐藏,如果有参数,定义的时候,必须要写参数,而且必须要有参数变量名
    void(^block2)(int) = ^(int a){
    };
  • 第三种 block返回可以省略,不管有没有返回值,都可以省略
    int(^block3)() = ^int{

        return 3;

    };

block类型:int(^)(NSString *)

    int(^block4)(NSString *) = ^(NSString *name){

        return 2;

    };

1.3、block调用

block1();

1.4、block快捷方式 inline

block开发使用场景(保存代码)

  • 2.1、block如何定义成属性

    • 2.1.1、block怎么声明,就如何定义成属性
      @property (nonatomic, strong) void(^block)();
    • 2.1.2、BlockType:类型别名
      typedef void(^BlockType)();
      @property (nonatomic, strong) BlockType block1;
  • block开发使用场景(传值)

Block内存管理

  • 4.1、面试题:
    block是不是一个对象?是一个对象
  • 4.2、如何判断当前文件是MRC,还是ARC
    • 1.dealloc 能否调用super,只有MRC才能调用super
    • 2.能否使用retain,release.如果能用就是MRC
  • 4.3、block的内存管理分两种情况:MRC和ARC
    • 4.3.1、MRC了解开发常识:

      1.MRC没有strong,weak,局部变量对象就是相当于基本数据类型(基本数据类型放在栈里,代码块结束就销毁)
      2.MRC给成员属性赋值,一定要使用set方法,不能直接访问下划线成员属性赋值
      解释:在set方法里会做些额外的处理,如果用_name就不会有relase和retain操作,如:

        @property (nonatomic, retain) NSString *name;
         - (void)setName:(NSString *)name
    {
        if (name != _name) {
            [_name release];
            _name = [name retain];
        }
    }
    ```
    
- 4.3.2、MRC:管理block
  -  1、只要Block引用外部局部变量,block放在栈里面.
 -  2、block只能使用copy,不能使用retain,使用retain,block还是在栈里面(代码块结束就销毁),而使用copy,block就在堆里面
解释:
  > ```            
          1、
            __block int a = 3;
      void(^block)() = ^{ 
        NSLog(@"调用block%d",a);
    };

此时block引用外部的局部变量,在栈里
2、
@property (nonatomic, copy) void(^block)();

  - MRC下:
- (void)viewDidLoad {

    [super viewDidLoad];

    __block int a = 3;

    

    void(^block)() = ^{

        

        NSLog(@"调用block%d",a);

    };

    

    self.block = block;

}

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

{

    self.block();

    

}
  • 4.3.3、ARC:管理block

ARC管理原则:
只要一个对象没有被强指针修饰就会被销毁,默认局部变量对象都是强指针,存放到堆里面
ARC:管理block
只要block引用外部局部变量,block放在堆里, block使用strong.最好不要使用copy

  • ARC下:
@property (nonatomic, strong) void(^block)();

//@property (nonatomic, copy) void(^block)();

- (void)viewDidLoad {

    [super viewDidLoad];
     

//    self.name = @"123";    

    int a = 3;
    

    void(^block)() = ^{
        

        NSLog(@"%d",a);
  

    };

    _block =  block;

    NSLog(@"%@",_block);

}

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

{

    _block();

}

思考?

  • 1.为什么block在堆里,也不能用weak来修饰?
    • 答:ARC下,默认局部变量对象都是强指针,block指针强引用block对象,代码块结束就会释放,所以需要对block对象再进行一次强引用。为什么要对局部变量进行一次强引用,就是为了防止代码块销毁
  • 2.为什么用strong不用copy
  • 答: @property (nonatomic, strong) NSString *name;
    现在这个视频讲的是对字符串不必用copy,因为不可变给不可变赋值,不用分配内存
- (void)setName:(NSString *)name

{

    _name = [name copy];

}

这个代码是copy要进行的操作,会在内部判断是否需要分布新的内存,如可变给不可变赋值需要分布内存,若不可变给不可变赋值就没必要分布内存

- (void)setName:(NSString *)name

{

    _name = name;

}

这个代码是strong要进行的操作,直接赋值
总结:
只要block没有引用外部局部变量,block放在全局区

      void(^block)() = ^{       

        NSLog(@"调用block%d");

    };   

    static int a = 3;(这个不是局部变量,这个static更改了a的生命周期)

    void(^block)() = ^{   

        NSLog(@"调用block%d",a);

    };

    //此时block没有引用外部的局部变量,在全局区里

Block循环引用

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

- (void)viewDidLoad {

    [super viewDidLoad];

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

    _block = ^{

        NSLog(@"%@",self);     

    };

    _block();

}

循环引用图:

825e1998-3c3c-492f-a407-df7139380bce.png

解析图:
图:self里有block属性,只想block变量,而block变量里有self,会对里面的强指针变量强引用一次,self就会强指向该对象,就会造成相互引用。
解决方法:

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

- (void)viewDidLoad {    

    [super viewDidLoad];

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

    __weak typeof(self) weakSelf = self;

    _block = ^{

       NSLog(@"%@",weakSelf);       

    };

    _block();

}

指针图:


e4ab9a31-6744-4090-93b4-67708e03f140.png

指针图解析:把self包装成弱指针,block就不会再强引用了

深入block循环利用:

  • 问题:若block里有延时操作,可能就已经销毁,需要再强引用来防止对象的销毁
@property (nonatomic, strong) void(^block)();

- (void)dealloc

{

    NSLog(@"ModalViewController销毁");

}

- (void)viewDidLoad {

    [super viewDidLoad];

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

    __weak typeof(self) weakSelf = self;
    

    _block = ^{

        __strong typeof(weakSelf) strongSelf = weakSelf;
        

        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

             NSLog(@"%@",strongSelf);
            

        });
        

    };
    

    _block();

}

指针图:

ba8ff633-71a7-4396-95b3-666a14e12ba3.png

解析图:
strongSelf指针对本对象强引用,__strong typeof(weakSelf) strongSelf 相当于局部变量,after block中就会用strongSelf指针对本对象强引用,最外层block执行完毕后,strongSelf指针会销毁、2s后after block会销毁之后本对象才会被销毁

Block变量传递

  • 如果是局部变量,Block是值传递(外面修改不影响里面)
- (void)viewDidLoad {

    [super viewDidLoad];

    int a = 3;      

    void(^block)() = ^{  

        NSLog(@"%d",a); //a为3       

    };

    a = 5; 

    block(); 

}
  • 如果是静态变量,全局变量,__block修饰的变量,block都是指针传递(外面的修改影响block里面的值)
- (void)viewDidLoad {

    [super viewDidLoad];    

    

    __block int a = 3;    

    void(^block)() = ^{ 

        NSLog(@"%d",a);    //值为5

    };

    a = 5;

    block(); 

}

Block开发使用场景(参数使用)

  • 把block当做参数,并不是马上就调用Block,什么时候调用,由方法内部决定
  • 什么时候需要把block当做参数去使用:做的事情由外界(非本类)决定,但是什么时候做由内部决定.
    需求:封装一个计算器,提供一个计算方法,怎么计算由外界决定,什么时候计算由内部决定.
- (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);

}

@implementation CacultorManager

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

    if (cacultorBlock) {

      _result =  cacultorBlock(_result);

    }

}

block开发中使用场景(返回值)

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

如: messay里的make.center.equalTo(ws.view);
解析:make.center.equalTo得到一个block,make.center.equalTo(ws.view)去调用block

  • self.test();
    • 解析:self.test();发两步:1、self.test是调用get方法,返回一个block,2、self.test()调用block
 - (void(^)())test
{
//    void(^block)() = ^{
//        
//    };
    return ^{
        NSLog(@"调用了block");
    };
}

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


- (void)viewDidLoad {

    [super viewDidLoad];

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

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

    // mgr.add(5)解析:mgr.add调用get方法返回一个block,mgr.add(5)调用的block是参数为5,mgr.add(5).add(5)需要返回mgr对象才可以一直.add调用下去

    mgr.add(5).add(5).add(5).add(5);

 }

@implementation CalculatorManager

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

{

    return ^(int value){

        _result += value;
        

        return self;

    };

}

相关文章

  • block相关

    是写在方法里的,在方法里定义个block,有返回值的,以;结尾,block只有被调用的时候才能执行 {} 里的代码...

  • Block相关

    bock常用写法: 1、无返回值 & 无参数 2、有返回值 & 无参数 3、有返回值 & 有参数 4、 block...

  • Block相关

    Block基本使用 1.1、block声明:返回值(^block变量名)(参数)void(^block)(); 1...

  • Block相关

    https://www.jianshu.com/p/4e79e9a0dd82

  • Block相关

  • Block相关

    Block 一:结构相关Block是一个包含了上下文变量的对象,该对象包含了_block_impl结构体,上下文变...

  • Block相关

    类型 1.NSGloabalBlock 全局block,存储在全局区 该block无参数,无返回值,内部也没有引用...

  • Block相关

    整理一下自己学到的知识,方便以后查看 使用block时什么情况会发生引用循环,如何解决? 一个对象中强引用了blo...

  • Block 初见

    Block 初见 介绍 iOS block 的相关知识 目录 Block 背景知识 Block 使用方式 Bloc...

  • block用法大全

    block语句块 如何解决block循环引用 高逼格理解block循环引用 block相关

网友评论

      本文标题:Block相关

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