2016-06-26 10:49:17 iuyo89007 阅读数 8976

注意:以下方法只可用于debug,而且在多线程等情况下返回值不是100%可信。

1.使用KVC

[obj valueForKey:@"retainCount"]

2.使用私有API

OBJC_EXTERN int _objc_rootRetainCount(id);
_objc_rootRetainCount(obj)

3.使用CFGetRetainCount

CFGetRetainCount((__bridge CFTypeRef)(obj))


2014-11-03 09:25:36 MIRAGE086 阅读数 765

英文原文:Automatic Reference Counting on iOS


自动引用计数(ARC)是在MacOS X 10.7与iOS 5中引入一项新技术,用于管理Objective-C中的对象。它废弃了显式的retain、release和autorelease消息,而且在两个平台的表现一致。

由于有限的内存以及手持设备续航能力的限制,iOS应用程序中的Objective-C对象的管理一直颇有挑战性。为了处理这些问题,苹果提出了一个方案——“自动引用计数”(ARC)。在这篇文章中,我会把ARC和显式的retain/release以及垃圾回收进行对比,除此之外还会展示如何在一个iOS项目中使用它,并且探讨一些ARC的使用准则。 

读者应当拥有Objective-C和Xcode IDE的使用经验。 

 

通过消息传送来实现

首先,我通过显示的消息传送来管理ObjC对象。我用alloc和init消息来创建对象(如图 1)。我发送retain消息来保持一个对象,并且发送release消息来释放掉它。通过alloc/init创建的ObjC对象会有一个内部的值为1的引用计数。retain消息会使这个引用计数加1,然而,release消息会使这个引用计数减1.当这个引用计数为0时,这个对象会自动销毁,释放它所持有的内存。 

 
Figure 1.


我们也可以用一个工厂方法来创建ObjC对象。这样就标记了这个对象是自动释放的,将他的指针加到自动释放池(如图 2)。我们可以通过autorelease消息来实现对alloc/init的对象达到发送release消息的目的。 

 
Figure 2.




在每一个事件周期中,自动释放内存池都会去检测自身的对象指针集。当它发现超出其作用域并且引用记数为1的对象,它就会通过发送一个release消息释放这个对象。当不想释放这个对象时,我们可以发送一个或多个retain消息给这个对象。否则,我们必须让这个对象发送的retain和release消息一样多,才能将它释放。 

显式发送消息的方式仍然是iOS应用程序中管理ObjC对象的一种有效方法。它一般不会花费很多精力,可以很容易的定位bug,同时拥有性能好的特点。 

在另一方面,显式发送消息的方式很容易导致出错。当retain和release消息不相等时,它会导致内存泄露或EXC_BAD_ACCESS错误。另外,显式地释放一个已经释放了的对象也会导致EXC_BAD_ACCESS错误。并且,对象容器(如数组,集合等)可能并不会对它包含的引用记数大于1的对象运行该对象的构造函数。
 

使用垃圾回收管理

MacOS X 10.5 (Leopard) 给我们另一个管理ObjC对象的方法— 垃圾回收。这里,每一个Cocoa应用程序得到自己的作为次级线程运行的收集服务  (Figure 3)。 

 
Figure 3.

这个服务标识所有在一起动就创建的根对象,然后跟踪每一个后来创建的对象。它检查每一个对象的范围以及对根对象的强引用。如果对象有这些特性,那么收集服务将它保留下来(用蓝色标记)。否则,它使用一个finalize消息释放这个对象(用红色标记)。

 

收集服务是保守的。当必须保证高性能时,它可以被中断,甚至暂停 。它是一个分代的服务。他假定最新被创建的对象寿命最短。 

通过类NSGarbageCollector来使用收集服务。使用这个类,我能够禁用这个服务或者改变它的行为。我甚至能指定新的根对象或者重置服务本身。


垃圾回收移除了显式的保留和释放消息的需要。它能够降低野指针也能够防止空指针。换句话说,它需要所有定制的ObjC对象被更新。清除代码必须进入到finalize方法,而不是 dealloc方法。ObjC对象也必须向他的父发送一个finalize消息。 

接下来,收集服务需要知道何时一个对象的引用是弱的。否则,他假设所有的引用都是强的。这可能导致循环引用和内存泄漏。这个服务也忽略使用withmalloc()创建的对象:那些对象应该被手动释放或者使用Cocoa函数NSAllocateCollectable()来创建。 

最后,这个服务依然会导致性能受到影响,尽管他是保守的。这就是垃圾回收在iOS上缺席的原因。 

 

进入 ARC

ARC是一种全新的方式,它拥有很多垃圾回收机制的优点,但却没有那样的性能损耗。 

从内部来看,ARC并不是一项运行时的服务。实际上它是由新的Clang front-end提供的两段过程。图4显示了这两段过程。在front-end段时,Clang检查每个预处理文件的对象和属性。然后它跟据一些固定的规则将正确的retain,release和autorelease语句加入其中。 

图4.

举例来说,如果对象被分配内存并处于一个方法当中,它会在这个方法的结尾处获得一个release语句。如果是一个类属性,它的release语句会加入到类的dealloc方法中。如果这个对象是用来返回的或者它是一个容器对象,它会加入一个autorelease语句。又如果这个对象是弱引用,把它放在一边不管它。

 

前端也为非局部对象插入保留语句。他更新所有使用@property指示符声明的访问器。他添加了对父的dealloc的调用,并且他报告任何的显式的管理调用和任何不清晰的所有权。 

在优化阶段,Clang 使修改过的代码遵从加载平衡。它统计每一个对象保留和释放的调用,然后把它们缩减到优化的最小值。这避免了过度的保留和释放,能够在性能上产生影响。

为了描述, 看看在Listing One中的实例代码。 

Listing One 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@class Bar;
@interface Foo
{
@private
    NSString *myStr;
}
@property(readonly) NSString *myStr;
  
- (Bar *)foo2Bar:(NSString *)aStr;
- (Bar *)makeBar;
//...
@end
  
  
@implementation Foo;
@dynamic myStr;
  
– (Bar *)foo2Bar:(NSString *)aStr
{
    Bar *tBar;
      
    if (![self.myStr isEqualToString:aStr])
    {
        myStr = aStr;
    }   
    return ([self makeBar]);
}
  
- (Bar *)makeBar
{
    Bar *tBar
    //...
    //... conversion code goes here
    //...
    return (tBar);
}
//...
@end
在这里,我展示了一个没有任何保留和释放消息的ObjC类。它有一个私有的属性myStr,它是一个NSString(第5行)的实例.它声明了一个只读的getter, 也命名为myStr(第7行).它定义了一个修饰符foo2Bar和一个内部函数makeBar(18-36行)。这个类也使用@class指示符导入了类Bar的header(第1行)。 
 

列表2列出了相同简单的经过ARC处理后的代码。 

列表2 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
@class Bar;
@interface Foo
{
@private
    NSString *myStr;
}
@property (readonly) NSString *myStr;
  
- (Bar *)foo2Bar:(NSString *)aStr;
- (Bar *)makeBar;
//...
@end
  
  
@implementation Foo;
@dynamic myStr;
  
– (Bar *)foo2Bar:(NSString *)aStr
{
    Bar *tBar;
      
    if (![self.myStr isEqualToString:aStr])
    {
        [aStr retain];
        [myStr release];
        myStr = aStr;
    }   
    return ([self makeBar]);
}
  
- (Bar *)makeBar
{
    Bar *tBar
    //...
    //... conversion code goes here
    //...
    [tBar autorelease];
    return (tBar);
}
//...
  
- (void)dealloc
{
    [myStr release];
    [super dealloc];
}
@end
类接口并没有被改变。但是它的foo2Bar被新加入了两行代码。一个语句发送一个release消息给属性myStr(行24)。另一个发送一个retain消息给参数aStr(行25)。makeBar函数在返回之前发送一个autorelease消息给局部变量tBar,并将tBar作为返回值。最后,ARC重写了类的dealloc方法。在这个方法中,它释放了属性myStr(行44)并且调用父类的dealloc方法(行45)。如果一个dealloc方法已经存在,ARC会将它的代码作适当更新。
 

因为ARC独自决定ObjC对象如何被管理,它省掉了开发类代码的时间。它阻止了任何野指针和空指针。它甚至能够基于文件来禁用。最后一个特征让程序员可以复用被证明是稳定的遗留代码。 

但是Clang编译器被构建在LLVM 3.0中,它只能在Xcode 4.2或者更新的版本中获得.对于ARC的优化的运行时支持也仅仅出现在MacOS X 10.7 (Lion) 和 iOS 5.0。在iOS 4.3中通过粘合代码使用ARC是可能的。在后来提供的不使用任何弱指针的二进制文件中使用ARC也是可能的。 

然后,ARC只对ObjC代码起作用。对于PyObjC和AppleScriptObjC代码没有任何效果。但是,它的确影响那些桥接PyObjC,ASOC类到Cocoa的底层ObjC对象。也值得注意的是,一些第三方的框架在使用ARC开启的编译的时候也可能会导致问题 。请确保在更新版本时联系框架的开发者。 


 

为ARC做准备

在一个iOS项目中有两个方法支持ARC。一个是使用ARC-enabled的模板创建项目。另一个是使用Xcode改写一个现存的项目。 

假设你想开始一个新的iOS项目。启动Xcode,从文件菜单里选择新项目。在新建对话框中 (Figure 5),选择一个项目模板(在这个例子中,单视图项目),点击Next查看项目选项。在界面的字段中输入项目名称,公司ID,以及类前缀。 然后勾选Use Automatic Reference Counting (Figure 6). 点击Next查看项目位置。设置位置和源代码仓库 (可选),然后点击Create创建项目本身。 

 
Figure 5.

 
Figure 6.

为了验证ARC是否被开启,在项目窗口中的组和文件面板中选择项目图标 (Figure 7).从Target Setting工具条中点击Build Settings。,然后点击那个工具条下边的All。向下滚动并且定位到设置组Apple LLVM computer 3.0 — Language。 查找条目Objective-C Automatic Reference Counting — 它的值应该是Yes. 

 
Figure 7.

 

如果你想将一个已经存在的iOS工程转化成ARC要怎样做呢?打开这个工程进入Xcode并且点击Edit菜单。从Refactor子菜单(Figure 8),选中Convert to Objective-C ARC...,会弹出另一个帮助对话框,进行相应的操作步骤。 

图8

点击Next按钮可以看到一个构建目标列表(图9)。选中一个目标并点击Precheck来开始重构工程。如果重构失败,Xcode会警示用户,并在工程窗口中列出相应的重构错误。 

图9

 

如果重构成功,Xcode将进入对比模式(如图 10)。这个帮助对话框分割成三个面板。左面的面板展示了涉及到的文件,默认是被选中的。中间的面板展示了源文件,右边的面板展示了修改后的文件。检查建议的改变并且点击Save提交他们或者点击Cancel放弃修改。无论如何请确保有一个代码的备份。否则,你将不能把工程文件还原到ARC之前的状态。 

 
图片 10.

如果你想从ARC中移除一些工程文件会怎么样?如果是这样,在Xcode是对比模式时取消文件旁边复选框的选中状态(看图10)。如果这个文件可以加入到重构工程中,在文件面板的分组中选中工程图标。点击Target Settings 面板中Build Phases,并且向下滚动找到Compile Sources分组(如图 11)。点击分组头选择要移除的文件。然后点击Compile Flags列并且在模态对话框中输入-fno-objc-arc。点击Done设置标记,它将在每个文件中出现。 

 
图片 11.

 

ARC指导方针

当从头开始写ObjC代码的时候,你应该确保代码与ARC兼容。代码必须给ARC完成工作所必要的线索。否则,他可能在错误的地方插入代码,或者更糟,他可能在代码中报告错误。 

这些是写ARC兼容代码的指导方针。这些Apple官方文档和博客文章被编辑放在文章的最后。  

  • 让ARC决定如何以及何时保留或者释放对象。
    如前所述,ARC前端捕获所有的显式的保留和释放消息。 他将把它们当做错误报告,并且你将不得不手动删除它们以便让项目可以编译。因此永远也不要发送保留或者释放消息给ObjC对象。永远不要使用retainCount消息去检查对象的保留状态,因为那个消息不再是可靠的。另外,不要使用@selector指令去调用对象的保留和释放方法。
    至于@property访问器,不使用assign,copy, retain特性来声明他们。让ARC决定给每一个访问器什么特性。 
  • 让ARC管理自动释放池和它的对象。
    再一次声明,ARC前端补货所有的显式的自动释放消息。确保从你的ObjC代码中排除掉这些消息。也不要使用NSAutoreleasePool去创建池。相反,使用@autorelease指令标记池的位置和的范围。这告诉前端插入为ARC优化过的创建和释放池的代码。
    考虑一下在Listing Three中的例子代码。

    Listing Three 

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    void main()
    {
        NSArray *tArgs = [[NSProcessInfo processInfo]
            arguments];
        unsigned tCnt, tLmt = [tArgs count];
          
        @autorelease
        {
            for (tCnt = 0; tCnt < tLmt; tCnt++)
            {
                @autorelease
                {
                NSString *tDat;
                NSString *tNom;
                  
                tNom = [tArgs objectAtIndex:tCnt];
                tDat = [[[NSString alloc]
                    initWithContentsOfFile:tNom]
                    autorelease];
                  
                // Process the file, creating and
                // autoreleasing more objects
                }
            }
          
        // Do more tasks, creating and autoreleasing
        // more objects
        }
          
        // Do whatever cleanup is needed
        exit (EXIT_SUCCESS);
    }
 
在这里,main()入口函数使用了两个自动释放池。第一个池出现在函数的开始位置(第7行),他一直保持活动状态直到函数结束(第28行). 任何被这个函数标记为自动释放的对象都进入到这个池中。 
第二个池出现在每一个for循环的开始处(11-23行). 当循环结束时,他释放这个池并且创建一个新的。在每一次循环中被标记为自动释放的对象进入到这个池中,而不是第一个池。 
  • 显式的声明任何弱的和非保留引用。
    ARC假定所有的对象引用都是强的。当然,有一些例外, 最好的例子就是窗口视图(Figure 12)。这个视图保持每一个子视图和他包含的widget的强引用。换句话说,每一个子视图和widget仅仅保持一个对父视图的弱引用。

     
    Figure 12.


 

然而,两个对象之间相互强引用是可能的。这种情况称为循环引用。考虑列表 4中的例子。 

列表 4 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@interface FooLink
{
    FooLink *fooNext;
    FooLink *fooPrev;
    NSData *fooData;
    NSInteger fooID;
}
@property(readwrite, assign) FooLink *nextLink;
@property(readonly) FooLink *prevLink;
 
- (NSData *)getData;
- (void)addToLink:(NSData *)aDat;
- (FooLink *)searchForLink:(NSInteger)anID;
- (BOOL)hasLink:(NSInteger )anID;
//...
@end

类FooLink实现了一个双向链表,每个节点拥有一个NSData对象。属性fooNext和fooPrev都指向另外的FooLink对象。由于两个指针形成了强引用,ARC将不会销毁这个对象。 

为了阻止这种事发生,声明其中一个属性为弱引用。在列表 5中,我在属性fooPrev前面加了一个__weak指令(第四行)。这样,当fooNext指向空并且FooLink对象超出范围时,ARC可以安全的给这个对象发送一个release消息。 

列表 5 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@interface FooLink
{
    FooLink *fooNext;
    __weak FooLink *fooPrev;
    NSData *fooData;
    NSInteger fooID;
}
@property(readwrite, assign) FooLink *nextLink;
@property(readonly) FooLink *prevLink;
 
- (NSData *)getData;
- (void)addToLink:(NSData *)aDat;
- (FooLink *)searchForLink:(NSInteger)anID;
- (BOOL)hasLink:(NSInteger )anID;
//...
@end
 

__weak指示符既可以声明弱引用,也可以声明空引用。另一个指示符__unsafe_unretained 声明弱引用,而不是空引用。如果你计划自己处理空引用,那么使用这个指示符。 但是一定要去处理,否则你将最终会内存泄露。 

当然还有另外的一些编译器指示符,但是前面两个是你经常会用到的。 

  • 避免转换ObjC对象到C指针。
    指向ObjC对象的指针式是一般的typeid的指针。为了把他们当做一个C-routine的输入,你可能可能转换这个指针如Listing Six (3-9行)所示。这里,我使用了工厂方法stringWithString创建了一个NSString实例。接着我映射它到一个整形指针,并且把它传递给doFoo。

    Listing Six 

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // Recasting an ObjC object pointer
    {
    id tStr;
    int *tPtr;
     
    tStr = [NSString stringWithString:@"foobar"];
    tPtr = (int *)tStr;
     
    doFoo(tPtr);
    }
     
    // Using a CFObject
    {
    CFStringRef tStr;
     
    tStr = CFSTR("foobar");
    doFoo(tStr);
    }
  •  
    但是,转换阻止ARC正确的管理对象。ARC将不知道什么时候去保留对象,什么时候释放对象。此外转换指针可能最终指向一个无效的对象。因此,不要转换,使用核心的基础APIs 去创建C兼容的对象。(14-17行). 
    • 避免将ObjC对象作为C结构体的字段。
      在一个C结构体中我们能够使用ObjC对象作为字段。Listing Seven的示例中的struct就有两个这样的字段(4-5行):一个是NSString实例,另一个是NSURL实例。如果 ObjC对象是自定义的,我们可能我们可能使用@def指示符渲染他的属性的可见性。

      Listing Seven 

      ?
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      // A C struct with ObjC fields
      typedef struct FooStruct
      {
          NSString *fooName;
          NSURL *fooPath;
          int fooCount;
          char *fooData;
      } Foo;
       
      // A C struct with CoreFoundation fields
      typedef struct BarStruct
      {
          CFStringRef *barName;
          CFURLRef *barPath;
          int barCount;
          char *barData;
      } Bar;
       
      // The C struct rewritten as an ObjC class.
      @interface BarClass
      {
          NSString *fooName;
          NSURL *fooPath;
          int fooCount;
          char *fooData;
      }
      //...property accessors goes here
      @end
      但是就是在这里,ARC将不能够管理在结构体中的ObjC对象。它可能不能识别对那些对象的引用也不能为那些对象提供正确的保留,释放和自动释放语句。 同样的,使用核心的基础APIs去为结构体创建对象(13-16行)。或者将这个结构体重写为一个简单的ObjC类(20-28行)。 
    • 自己管理所有的C和CF对象。
      就像垃圾回收,ARC忽略所有使用stdlib和核心基础APIs创建的对象。他将不插入被用来创建和释放结构体或者联合体的malloc()和free()调用。也不会为CF对象插入CFRetain()和CFRelease()调用。
      确保自己添加提供这些调用。小心平衡得为每一个malloc()调用一个free()并且为每一个CFRetain()调用一个CFRelease()。也确保避免在同一个对象上调用两次free()或者CFRelease()。 

     

    总结

    自动引用计数是一个创新的管理在MacOS X 10.7和iOS 5上的ObjC对象的方法。它远离了显式的保留,释放以及自动释放消息,并且他降低了潜在的内存泄露和空指针。它提供了优化的自动释放池,避免了垃圾回收那样的性能开销。他的行为在两个平台是一致的。但是,ARC有很多方面太复杂以至于不能在这篇文章中覆盖到。为了学习了解更多的与ARC相关的东西,请查看下边的参考列表。


    原文链接:http://www.oschina.net/translate/automatic-reference-counting-on-ios
    2019-11-17 22:24:19 u012094456 阅读数 41

    MRC(手动引用计数)和ARC(自动引用计数)

    1、MRC:alloc,retain,release,retainCount,autorelease,dealloc
    2、ARC:

    • ARC是LLVM和Runtime协作的结果
    • ARC禁止手动调用retain,release,retainCount,autorelease关键字
    • ARC新增weak,strong关键字

    3、引用计数管理:

    • alloc: 经过一系列函数调用,最终调用了calloc函数,这里并没有设置引用计数为1
    • retain: 经过两次哈希查找,找到其对应引用计数值,然后将引用计数加1(实际是加偏移量)
    • release:和retain相反,经过两次哈希查找,找到其对应引用计数值,然后将引用计数减1
    • dealloc:

    4、弱引用管理:

    • 添加weak变量:通过哈希算法位置查找添加。如果查找对应位置中已经有了当前对象所对应的弱引用数组,就把新的弱引用变量添加到数组当中;如果没有,就创建一个弱引用数组,并将该弱引用变量添加到该数组中。

    • 当一个被weak修饰的对象被释放后,weak对象怎么处理的?
      清除weak变量,同时设置指向为nil。当对象被dealloc释放后,在dealloc的内部实现中,会调用弱引用清除的相关函数,会根据当前对象指针查找弱引用表,找到当前对象所对应的弱引用数组,将数组中的所有弱引用指针都置为nil。

    5、自动释放池:

    在当次runloop将要结束的时候调用objc_autoreleasePoolPop,并push进来一个新的AutoreleasePool

    AutoreleasePoolPage是以栈为结点通过双向链表的形式组合而成,是和线程一一对应的。
    内部属性有parent,child对应前后两个结点,thread对应线程 ,next指针指向栈中下一个可填充的位置。

    • AutoreleasePool实现原理?

    编译器会将 @autoreleasepool {} 改写为:

    void * ctx = objc_autoreleasePoolPush;
        {}
    objc_autoreleasePoolPop(ctx);
    
    • objc_autoreleasePoolPush:
      把当前next位置置为nil,即哨兵对象,然后next指针指向下一个可入栈位置,
      AutoreleasePool的多层嵌套,即每次objc_autoreleasePoolPush,实际上是不断地向栈中插入哨兵对象。

    • objc_autoreleasePoolPop:
      根据传入的哨兵对象找到对应位置。
      给上次push操作之后添加的对象依次发送release消息。
      回退next指针到正确的位置。

    2014-09-14 19:27:22 id357015100 阅读数 504

    ARC

    ARCAutomatic Reference Counting(自动引用计数)的缩写,是IOS5一同推出的新特性,但是IOS4.3也支持ARC,只是不能使用weak。

    使用ARC,不需要再retain、release、autorelease,因为编译器会在合适的地方自动的插入retain、release。

    ARC的黄金法则

    1.只要还有一个变量(指针)指向对象,对象就会保持在内存中;

    2.__strong告诉编译器此处添加retain,__strong可以省略。

    NSString *string = @"Ray"

    __strong NSString *string = @"Ray"

    以上两种写法是等同的。

    3.在ARC中。dealloc方法中不允许调用[super deslloc]

    4.在ARC中,不允许使用retainCount属性、打印引用计数

    5.在ARC中,不允许使用retain、release、autorelease,可以使用copy。


    strong的使用

    有两个指针指向了字符串对象@"Ray"

    NSString *firstName = @"Ray";

    self.textField.text = firstName;

    当self.textField.text 指向字符串@"RayMan”,会先对@"Ray”对象release;

    当firstName指向了@""字符串对象时,先会对原来指向的@"Ray”对象release。此时@"Ray”对象就没有一个指针指向它,引用计数也就是0,因此销毁。


    weak的使用

    weak修饰的变量不会将对象retain;

    weak变量指向的对象如果销毁了,则weak所修饰的变量自动变为nil;


    strong与weak

    在引用strong修饰的对象时,该对象会被retain;

    默认所有实例变量和本地变量都是strong类型的指针;(本地变量

    weak修饰的对象不会对此对象retain,相当于手动管理的assign。


    在IOS4.3中ARC不能使用weak,替代者为:__unsafe_unretained,__unsafe_unretained与weak的功能一致,区别在于当指向的对象销毁后,不会将变量设置为nil;这样就有可能调用野指针。


    weak可以防止循环引用,典型的就是delegate模式

    代理对象delegate应该设置成weak;


    property的修饰符总结

    1.strong:等同于retain,属性成为对象的拥有者

    2.weak:属性是weak pointer,当对象释放时会自动设置为nil,记住Outlet应该使用weak

    3. __unsafe_unretained:等同于之前的assign,只有IOS4才能使用

    4.copy:和之前的copy一样,复制一个对象并创建strong关联

    5.assign:对象不能使用assign,但是原始(bool、int、float)仍然可以使用。


    Block在ARC中的内存管理

    在手动管理内存时,使用如下方式防止循环引用

    __block SendViewContronller *this = self;
    _faceView = [[FaceScrollView alloc] initWithBlock:^(NSString *faceName){
    this.textView.text = @"test";
    }];

    ARC中不能这样使用,以为变量this默认是strong引用,即使标记为__block也仍然为strong类型的引用,这时候__block的唯一功能是允许你修改已捕获的变量(没有__block则变量是只读)

    __weak SendViewContronller *weakSelf = self;
    __faceView = [[FaceScrollView alloc] initWithBlock:^(NSString *faceName){
    __strong SendViewContronller *strongSelf = weakSelf;
    if(strongSelf != nil){
    strongSelf.textView.text = @"test";
    }
    }];
    

    在ARC环境中使用Block,推荐采用如下代码模板:

    __weak id weakSelf = self;
    block = ^(){
    __strong id strongSelf = weakSelf;
    if(strongSelf != nil){
    //do stuff with strongSelf
    }
    };
    


    ARC中使用Toll-Free Bridging

    Toll-Free Bridging,简称TFB。是一种允许某些objc类与其对应的CoreFoundation类之间可以互换使用的机制。

    比如:NSString与CFString是桥接的,这意味着可以将任意的NSString当作CFString使用,也可以将任意的CFString当作NSString使用。

    ARC只能对OC对象进行内存管理,CFString桥接成NSString对象之后,此对象的内存管理该如何让管理?

    在ARC中,CFString桥接成NSString使用__bridge_transFer, __bridge_transFer的作用将其他类型的对象转变成为一个OC对象,由ARC管理;与__bridge_transFer相同作用的还有CFBridgingRelease。

    __bridge_retained的使用:NSString桥接成CFString用__bridge_retained,



    对于某些我们不希望使用 ARC 的文件,例如第三方库源文件,可以在 Project Settings -> Build Phases 中,对这些文件选中 -fno-objc-arc 标志。这样 Xcode 编 译项目时,这些文件就不会使用 ARC, -fobjc-arc 标志是允许使用ARC
















    2019-03-08 14:48:51 weixin_43883776 阅读数 45

    在ARC环境下,iOS不允许通过obj.returnCount的方式直接输出引用计数。

    使用如下代码

    LHSimpleObject * simpObject = [LHSimpleObject alloc];
        NSLog(@"returnCount = %ld",CFGetRetainCount((__bridge CFTypeRef)(simpObject)));
        simpObject = [simpObject init];
        NSLog(@"returnCount = %ld",CFGetRetainCount((__bridge CFTypeRef)(simpObject)));
    

    注意结尾处一共三个有括号
    注意结尾处一共三个有括号
    注意结尾处一共三个有括号

    在这里插入图片描述

    IOS自动引用计数概述

    博文 来自: YT111222466243360
    没有更多推荐了,返回首页