ARC与MRC的block有着一些区别,笔记整理ARC的block,仅仅是自己参考的笔记,详情请参考 http://www.cnbluebox.com/?p=255

 

在开始之前,请新建一个Model类,写几个如下的属性,用于后面测试block的特性.

ARC下block使用情况_强引用

ARC下block使用情况_循环引用_02

 

 

Block的类型与内存管理

根据Block在内存中的位置分为三种类型NSGlobalBlock,NSStackBlock, NSMallocBlock。

  • NSGlobalBlock:类似函数,位于text段;
  • NSStackBlock:位于栈内存,函数返回后Block将无效;
  • NSMallocBlock:位于堆内存。

 

ARC下block使用情况_循环引用_03

从打印信息处可以看出,该block是一个__NSGlobalBlock__.

 

ARC下block使用情况_block_04

虽然只是简单的改了一下,但很明显,刚刚的__NSGlobalBlock__已经变成了__NSMallocBlock__,此处我们可以得知,在处理对象时,block会malloc的.

 

我们使用弱引用集合NSHashTable来验证,一个block的强引用的情况.

#import <Foundation/Foundation.h>

@interface YX_NSHashTable : NSObject

+ (void)add:(id)obj;
+ (BOOL)contain:(id)obj;
+ (NSArray *)allObjs;

@end
#import "YX_NSHashTable.h"

static NSHashTable *table = nil;

@implementation YX_NSHashTable

+ (void)initialize
{
    if (self == [YX_NSHashTable class])
    {
        table = [NSHashTable weakObjectsHashTable];
    }
}

+ (void)add:(id)obj
{
    [table addObject:obj];
}

+ (BOOL)contain:(id)obj
{
    return [table containsObject:obj];
}

+ (NSArray *)allObjs
{
    return [table allObjects];
}

@end

ARC下block使用情况_强引用_05

从打印信息还看不出什么东西出来-_-!!

 

ARC下block使用情况_ios_06

将block设置成copy属性后,很明显,还没运行就已经提示了循环引用的问题.

控制器强引用了一个block,而该malloc的block也强引用了控制器.所以,导致了循环引用的问题.

 

堆内存的一个明显的特性就是:他会强引用block中的对象,如果该block被其他不会被释放的东西给强引用了,就会导致循环引用.

 

问:ARC支持dispatch_queue吗?

http://stackoverflow.com/questions/8618632/does-arc-support-dispatch-queues/8619055#8619055

If your deployment target is lower than iOS 6.0 or Mac OS X 10.8

You need to use dispatch_retain and dispatch_release on your queue. ARC does not manage them.

If your deployment target is iOS 6.0 or Mac OS X 10.8 or later

ARC will manage your queue for you. You do not need to (and cannot) use dispatch_retain or dispatch_release if ARC is enabled.

结论:如果你的iOS编译的target是iOS6.0+,ARC支持dispatch_queue.

 

问:如何才能在block中不至于造成泄露呢?

即使是NSMallocBlock也不一定会泄露,但是如果是一个copy属性的block,它一定是NSMallocBlock,这个就需要十分注意.出现在这个block中的对象,是会被这个包含这个block的对象给强引用的.如果这个对象是个单例而不会被释放掉,那就泄露了.

 

问:这种block会导致_model对象泄露吗?

 ARC下block使用情况_强引用_07

 因为block里面出现了对象,这个block变成了NSMallocBlock,理论上,_model会在该block的生命周期中一直被持有.直到它被销毁.

 

问:方法中的block是怎么回事呢?

 ARC下block使用情况_iOS_08

方法中的block是栈block,不用担心会被强引用.

 

问:MRC中的__block与ARC中的__weak有啥联系?

http://stackoverflow.com/questions/7853915/how-do-i-avoid-capturing-self-in-blocks-when-implementing-an-api

The __block keyword marks variables that can be modified inside the block (we're not doing that) but also they are not automatically retained when the block is retained (unless you are using ARC). If you do this, you must be sure that nothing else is going to try to execute the block after the MyDataProcessor instance is released. (Given the structure of your code, that shouldn't be a problem.) Read more about __block.

If you are using ARC, the semantics of __block changes and the reference will be retained, in which case you should declare it __weak instead.

在MRC中, __block 可以让一个变量在 block 中进行修改而不会被这个 block retain.

在ARC中, __weak 才能让一个变量在 block 中不被这个block强引用.

__block是在MRC中使用的.

__weak是在ARC中使用的.