zoukankan      html  css  js  c++  java
  • OC内存管理

    一、MRC  手动引用计数

      一个对象 alloc 之后其引用计数为1,需要对应一个 release 操作,此外,每有一个 retain 操作也要对应一个 release 操作。当一个对象的引用计数为0时(可以通过 retainCount 来获取,但不一定准确),就会销毁该对象,并调用该对象的 dealloc 方法。

      对于对象组合的情况,当一个对象使用另一个对象时,需要使其引用计数+1,比如set方法,但如果set前后为同一个对象,会导致引用计数变多,此时需要判断set的新对象不是原成员对象,然后对原成员对象 release ,而对新对象进行 retain,该操作可以通过 @property (retain) 来智能完成。

      当两个对象互相引用时,向上面的操作也会使引用计数错误(多1),此时可以将其中一个对象的引用设置成 assign ,并在其 dealloc 函数中取消该成员的 release 操作。

      整体代码如下:

     1 #import <Foundation/Foundation.h>
     2 
     3 @class Room;
     4 @class User;
     5 
     6 /******************************/
     7 @interface User : NSObject
     8 
     9 //@property(nonatomic,retain) Room *room;
    10 @property(nonatomic,assign) Room *room;
    11 
    12 @end
    13 
    14 @implementation User
    15 
    16 - (void)dealloc
    17 {
    18     NSLog(@"%s",__func__);
    19     //[_room release];
    20     [super dealloc];
    21 }
    22 
    23 @end
    24 
    25 /******************************/
    26 @interface Room : NSObject
    27 
    28 @property(nonatomic,retain)User *user;
    29 
    30 @end
    31 
    32 @implementation Room
    33 
    34 - (void)dealloc
    35 {
    36     NSLog(@"%s",__func__);
    37     
    38     [_user release];
    39     [super dealloc];
    40 }
    41 @end
    42 
    43 /******************************/
    44 int main(int argc, const char * argv[]) {
    45     User *user = [[User alloc] init];
    46     Room *room = [[Room alloc] init];
    47     user.room = room;
    48     room.user = user;
    49     
    50     [user release];
    51     [room release];
    52 }

       自动释放池是以栈的结构存在的,先进后出。通过 @autoreleasepool 代码段创建自动释放池,在代码段内调用对象的 autorelease 方法就可以将对象放入自动释放池,在自动释放池生命周期结束时,会将该对象的引用计数-1。改写 main 函数如下:

     1 int main(int argc, const char * argv[]) {
     2     @autoreleasepool {
     3         User *user = [[[User alloc] init] autorelease];
     4         Room *room = [[[Room alloc] init] autorelease];
     5         
     6         user.room = room;
     7         room.user = user;
     8         
     9         //[user release];
    10         //[room release];
    11     }
    12     
    13     //IOS5之前的老代码还可以这样创建自动释放池,现在不推荐,能看懂即可。
    14     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    15     //coding
    16     [pool release];
    17     
    18     return 0;
    19 }

     

      因为自动释放池使用的是延迟释放机制,所以不推荐将非常占内存的对象交给自动释放池管理,此外还有一些细节,比如不适宜在循环体内创建的对象交给同一个自动释放池管理。 自动释放池可以嵌套,而自动释放池也是栈结构,将一个对象进行 autorelease 操作,会自动将该对象放于栈顶的释放池进行管理。

      Foundation 库中几乎所有的类工厂方法,都是内部使用了 autorelease 方法。  

     

    二、ARC  自动引用计数

      是编译器特性而不是运行时特性,不同于其它语言中的垃圾回收。它不允许程序员在程序手动调用 retain/release/autorelease 方法。

      ARC的判断原则:只要还有一个强指针(__strong,对应的弱指针为 __weak)变量指向对象,对象就会保持在内存中。比如唯一的强指针变量超出生命周期,或者手动设置该强指针变量为 nil,都会触发 ARC 销毁指向的对象。所以开发中,不要使用一个弱指针保存一个刚刚创建的对象,因为一创建就被销毁了。

      ARC中,如果一个对象想拥有另一个对象,只需要用一个强指针指向该对象,@property 中不使用 retain,而是使用 strong/weak/assign。

      与 MRC 类似,当两个对象互相引用时,则一边使用 strong ,一边使用 weak。

      Xcode 支持将 MRC 项目转化成 ARC 项目,也可以自己转换,上面的例子转成 ARC 项目如下:

     1 #import <Foundation/Foundation.h>
     2 
     3 @class Room;
     4 @class User;
     5 
     6 /******************************/
     7 @interface User : NSObject
     8 
     9 @property(nonatomic,weak) Room *room;
    10 
    11 @end
    12 
    13 @implementation User
    14 
    15 - (void)dealloc
    16 {
    17     NSLog(@"%s",__func__);
    18 }
    19 
    20 @end
    21 
    22 /******************************/
    23 @interface Room : NSObject
    24 
    25 @property(nonatomic,strong)User *user;
    26 
    27 @end
    28 
    29 @implementation Room
    30 
    31 - (void)dealloc
    32 {
    33     NSLog(@"%s",__func__);
    34     
    35 }
    36 @end
    37 
    38 /******************************/
    39 int main(int argc, const char * argv[]) {
    40     User *user = [[User alloc] init];
    41     Room *room = [[Room alloc] init];
    42     
    43     user.room = room;
    44     room.user = user;
    45     return 0;
    46 }

     

  • 相关阅读:
    查看kafka在zookeeper中节点信息和查看方式
    安装单机版redis
    一 Redis 简介 和存储
    Spark消费kafka的直连方式
    Streaming 累加器和广播变量 和sql
    sparkStreaming转换算子02
    DStreams输入 从kafka消费数据 直连
    关于上下文图
    2018年春季个人阅读计划
    问题账户需求分析
  • 原文地址:https://www.cnblogs.com/tianyajuanke/p/7324665.html
Copyright © 2011-2022 走看看