美文网首页
Block的类型

Block的类型

作者: 程序萌 | 来源:发表于2017-05-03 09:17 被阅读0次
block常见类型(3种):
  • NSGlobalBlock:全局的静态block 没有访问外部变量

    image.png
  • NSMallocBlock 保存在堆中的block 此类型blcok是用copy修饰出来的block 它会随着对象的销毁而销毁,只要对象不销毁,我们就可以调用的到在堆中的block

@interface Person : NSObject
@property(nonatomic,copy) void(^mallocBlock)(void);
@end
image.png
  • NSStackBlock:保存在栈中的block,没有用copy去修饰并且访问了外部变量,会在函数调用结束被销毁 (但是要在MRC模式下) ARC改MRC方法
    在ARC中的NSStackBlock:
需要用assign去修饰Block(测试用,工作中用copy最好)
@property(nonatomic,assign) void(^mallocBlock)(void);
NSLog(@"%@",[person.mallocBlock class]);
//打印结果
block[22533:1198598] __NSStackBlock__
//注意一下,在之前iOS8之前,如果用retain去修饰Block和打印结果和assign是一样的
//但是之后retain修饰Block打印结果就变成了__NSMallocBlock__(应该是苹果修改了)
//只是警告:Retain'ed block property does not copy the block - use copy attribute instead 让我们使用copy去修饰
// 但是用strong去修饰Block,打印结果和copy一致,并且不会报错
NSLog(@"StackBlock 当前类型-- %@",^{
        NSLog(@"%d",a);
    });
//打印结果:  
// StackBlock 当前类型-- <__NSStackBlock__: 0x7ffee1f3ca40>

Block在ARC下的内存管理

在ARC默认情况下,Block的内存存储在堆中,ARC会自动进行内存管理,程序员只需要避免循环引用即可

在Block的内存存储在堆中时,如果在Block中引用了外面的对象,会对所引用的对象进行强引用,但是在Block被释放时会自动去掉对该对象的强引用,所以不会造成内存泄漏

如果对象内部有一个Block属性,而在Block内部又访问了该对象,那么会造成循环引用,解决循环引用的办法是使用一个弱引用的指针指向该对象,然后在Block内部使用该弱引用指针来进行操作,这样避免了Block对对象进行强引用
解决循环引用的方式一:

@interface Person : NSObject
@property(nonatomic,copy) void(^mallocBlock)(void);
@property(nonatomic,copy) NSString * str;
@end
  Person * person = [[Person alloc] init];
  person.str = @"外部属性";
  __weak Person * personWeak = person;
  person.mallocBlock = ^{
        NSLog(@"访问外部变量 %@ 则变成mallocBlock",personWeak.str);
  };
  person.mallocBlock();
@implementation Person
-(void)dealloc{
    NSLog(@"释放成功");
}
@end

解决循环引用的方式二:

 Person * p = [[Person alloc] init];
    //这里用 __block去修饰,是为了在block内部可以对weakP进行修改
    __block Person * weakP = p;
    p.myBlock = ^{
         NSLog(@"%@",weakP.myBlock);
        //通过__block修饰可以对weakP进行修改
        weakP = nil;
    };
    p.myBlock();

解决循环引用的方式三(优雅的方式):

@interface Person : NSObject
//定义一个有参数的block类型的成员属性,参数类型是Person(也就是自身的类型)
@property(nonatomic,copy) void(^myBlock)(Person*);
@end

   Person * p = [[Person alloc] init];
    p.myBlock = ^(Person * weakP) {
        NSLog(@"%@",weakP);
    };
     //需要传入一个类型为Person的参数,将p传进去
    p.myBlock(p);

block代码块中修改局部变量

直接在block代码中修改局部变量,会报出错误!
错误信息:Variable is not assignable (missing __block type specifier)
变量不可分配(缺少__block类型说明符)


image.png

所以正确的修改方式是 在局部变量前加__block

//__block 底层实现:用__block修饰的对象,会修改它的指针地址
 __block  int a =1;
    NSLog(@"外部%p",&a);
    void(^myBlock)(void) = ^{
            a++;
         NSLog(@"%d",a);
        NSLog(@"内部%p",&a);
    };
    myBlock();
NSLog(@"最后外部%p",&a);
//打印结果:
//外部0x7ffee6e21a28
// 2
// 内部0x60400023b9f8
//最后外部0x60400023b9f8
可以很清楚的看到,用__block修饰以后a的指针地址发生了改变。

如果先执行 block,代码块中局部变量会保持之前的值,之后再去更改局部变量的值,对代码块的内容无影响(需要注意)

   int a = 1;
    void(^editBlcok)(void) = ^{
        NSLog(@"%d",a);
    };
    a = 10;
    editBlcok();
// 控制台输出 1 ;

Block在MRC下的内存管理

默认情况下,Block的内存存储在栈中,不需要开发人员对其进行内存管理

在Block的内存存储在栈中时,如果在Block中引用了外面的对象,不会对所引用的对象进行任何操作

如果对Block进行一次copy操作,那么Block的内存会被移动到堆中,这时需要开发人员对其进行release操作来管理内存

如果对Block进行一次copy操作,那么Block的内存会被移动到堆中,在Block的内存存储在堆中时,如果在Block中引用了外面的对象,会对所引用的对象进行一次retain操作,即使在Block自身调用了release操作之后,Block也不会对所引用的对象进行一次release操作,这时会造成内存泄漏

为了不对所引用的对象进行一次retain操作,可以在对象的前面使用下划线下划线block来修饰。

__block Person *p = [[Person alloc] init];
        
void(^myBlock)() = ^{
    NSLog(@"------%@", p);
};
myBlock();

总结:

__block在MRC下有两个作用

  1. 允许在Block中访问和修改局部变量
  2. 禁止Block对所引用的对象进行隐式retain操作

__block在ARC下只有一个作用

  1. 允许在Block中访问和修改局部变量

__weak 解决ARC下的循环引用

如果对象内部有一个Block属性,而在Block内部又访问了该对象,那么会造成循环引用

相关文章

  • iOS原理篇(五):Block探究

    Block原理 Block变量捕获 Block类型 copy操作和Block内部访问对象类型的变量 __block...

  • 9 Block详解

    1.明白如何定义block类型 定义Block类型: typedef 返回值类型 Block名字 参数 block...

  • iOS block 为什么官方文档建议用 copy 修饰

    一、block 的三种类型block 三种类型:全局 block,堆 block、栈 block。全局 block...

  • iOS 常见面试题 -- block

    一、block的本质 二、block的类型 block 有三种类型分别如下: 如何区分block的类型 三、blo...

  • Block类型和捕获变量

    Block类型 1:类型区别特征 Block是OC的对象,他也有类型,我在打印[block class]的时候可以...

  • Block

    Block的变量捕获(capture) Block的类型 如何区分Block的类型 MRC:Global:没有访问...

  • 主题四《Block》

    1、block的本质 2、block的捕获 3、block的类型 4、block的copy 5、对象类型的auto...

  • iOS Block

    Block block 类型 block主要有三种类型 NSGlobalBlock:全局block,存储在全局区 ...

  • iOS底层:Block

    block的本质 block的变量捕获(capture) block的类型 block有3种类型,可以通过调用cl...

  • Block实现原理

    主要介绍block的类型和底层分析 block类型 block主要由三种类型 NSGlobalBlock:全局bl...

网友评论

      本文标题:Block的类型

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