zoukankan      html  css  js  c++  java
  • Object-C——内存管理

    一、计数器

       (一)、引用计数器的基本操作

            1、 方法的基本使用
              ①  retain :计数器+1,会返回对象本身
              ②  release :计数器-1,没有返回值
              ③  retainCount :获取当前的计数器
              ④ dealloc
                 * 当一个对象要被回收的时候,就会调用
                 * 一定要调用[super dealloc],这句调用要放在最后面

     1 #import "Person.h"
     2 
     3 @implementation Person
     4 
     5 
     6 // 当一个Person对象被回收的时候,就会自动调用这个方法
     7 - (void)dealloc
     8 {
     9     NSLog(@"Person对象被回收");
    10     
    11     // super的dealloc一定要调用,而且放在最后面
    12     [super dealloc];
    13 }
    14 
    15 @end


            2、 概念
             ①  僵尸对象 :所占用内存已经被回收的对象,僵尸对象不能再使用
             ②  野指针 :指向僵尸对象(不可用内存)的指针,给野指针发送消息会报错(EXC_BAD_ACCESS)
             ③  空指针 :没有指向任何东西的指针(存储的东西是nil、NULL、0),给空指针发送消息不会报错

              3、代码举例

     1 #import <Foundation/Foundation.h>
     2 #import "Person.h"
     3 
     4 int main()
     5 {
     6     // 1
     7     Person *p = [[Person alloc] init];
     8     
     9     //NSUInteger c = [p retainCount];
    10     
    11     //NSLog(@"计数器:%ld", c);
    12     
    13     
    14     // 2 retain方法返回的是对象本身
    15     [p retain];
    16     
    17     // 1
    18     [p release];
    19     
    20     // 0 野指针:指向僵尸对象(不可用内存)的指针
    21     [p release];
    22     
    23     [p retain];
    24     
    25     // -[Person setAge:]: message sent to deallocated instance 0x100109a10
    26     // 给已经释放的对象发送了一条-setAge:消息:
    27     p.age = 10;
    28     //[p setAge:10];
    29     
    30     // 指针p变成空指针
    31     //p = nil;
    32     
    33     // EXC_BAD_ACCESS : 访问了一块坏的内存(已经被回收、已经不可用的内存
    34     // 野指针错误
    35     // OC不存在空指针错误,给空指针发送消息,不报错
    36     [p release];
    37     [p release];
    38     [p release];
    39     [p release];
    40     
    41     [nil release];
    42     
    43     return 0;
    44 }

    (二) 多个对象之间的内存管理

           1、 你想使用(占用)某个对象,就应该让对象的计数器+1(让对象做一次retain操作)
           2、 你不想再使用(占用)某个对象,就应该让对象的计数器-1(让对象做一次release)
           3、 谁retain,谁release
           4、 谁alloc,谁release

     1 // b-1
     2     Book *b = [[Book alloc] init];
     3     // p-1
     4     Person *p1 = [[Person alloc] init];
     5     
     6     //p1想占用b这本书
     7     // b-2
     8     [p1 setBook:b];
     9     
    10     // p-0
    11     // b-1
    12     [p1 release];
    13     p1 = nil;
    14     
    15     // b-0
    16     [b release];
    17     b = nil;

     (三)、set方法的内存管理

        1、内存管理代码规范:
            ①  只要调用了alloc,必须有release(autorelease)
            ②  对象不是通过alloc产生的,就不需要release

        2、set方法

            ① 代码规范实现

     1 //基本数据类型:直接复制
     2  - (void)setAge:(int)age
     3  { 
     4     _age = age;
     5  }
     6  
     7 // OC对象类型
     8  - (void)setCar:(Car *)car
     9  {
    10     // 1.先判断是不是新传进来对象
    11     if ( car != _car )
    12     {
    13         // 2.对旧对象做一次release
    14         [_car release];
    15  
    16         // 3.对新对象做一次retain
    17         _car = [car retain];
    18     }
    19  }

         3、dealloc方法的代码规范实现

    1 //一定要[super dealloc],而且放到最后面
    2 // 对self(当前)所拥有的其他对象做一次release
    3  - (void)dealloc
    4  {
    5     [_car release];
    6     [super dealloc];
    7  }

      (四) @property参数

           1、 控制set方法的内存管理

                *retain : release旧值,retain新值(用于OC对象)

    // retain : 生成的set方法里面,release旧值,retain新值
    @property (retain) Book *book;
    @property (retain) NSString *name;

               *assign : 直接赋值,不做任何内存管理(默认,用于非OC对象类型)

    @property ( assign) int height;

                *copy   : release旧值,copy新值(一般用于NSString *)

            2、控制生成或者不生成set方法

                 *readwrite :同时生成set方法和get方法(默认)

                 *readonly  :只会生成get方法

    @property (readwrite, assign) int height;

             3、多线程管理

                 *atomic    :性能低(默认)

                 *nonatomic :性能高

    @property (nonatomic, assign, readwrite) int weight;

              4、控制set方法和get方法的名称

                  *setter : 设置set方法的名称,一定有个冒号:

                  *getter : 设置get方法的名称

    // 返回BOOL类型的方法名一般以is开头
    @property (getter = isRich) BOOL rich;

      (五) 循环引用

           1、 @class

              ①  作用:仅仅告诉编译器,某个名称是一个类
              ②  开发中引用一个类的规范
                *在.h文件中用@class来声明类

     1 #import <Foundation/Foundation.h>
     2 #import "Card.h"
     3 // @class仅仅是告诉编译器,Card是一个类
     4 //@class Card;
     5 
     6 @interface Person : NSObject
     7 
     8 @property (nonatomic, retain) Card *card;
     9 
    10 @end


                * 在.m文件中用#import来包含类的所有东西

     1 #import "Person.h"
     2 #import "Card.h"
     3 
     4 @implementation Person
     5 
     6 - (void)dealloc
     7 {
     8     NSLog(@"Person被销毁了");
     9     [_card release];
    10     
    11     [super dealloc];
    12 }
    13 
    14 @end

        2、循环retain
           ①问题

              *A对象retain了B对象,B对象retain了A对象

              *这样A、B对象永远无法释放

           ②两端循环引用解决方案
             * 一端用retain
             * 一端用assign          


      (六)、 autorelease

               1、autorelease的基本用法
                  ①  会将对象放到一个自动释放池中
                  ②  当自动释放池被销毁时,会对池子里面的所有对象做一次release操作
                  ③  会返回对象本身
                  ④  调用完autorelease方法后,对象的计数器不变
     
                2、autorelease的好处
                  ①  不用再关心对象释放的时间
                  ②  不用再关心什么时候调用release
     
               3、autorelease的使用注意
                  ①  占用内存较大的对象不要随便使用autorelease
                  ②  占用内存较小的对象使用autorelease,没有太大影响
               4、错误写法
                  ①  alloc之后调用了autorelease,又调用release

    1  @autoreleasepool
    2  {
    3     // 1
    4     Person *p = [[[Person alloc] init] autorelease];
    5  
    6     // 0
    7     [p release];
    8  }
    9  

               ②  连续调用多次autorelease

    1 @autoreleasepool
    2  {
    3     Person *p = [[[[Person alloc] init] autorelease] autorelease];
    4  }

              5、自动释放池
               ①  在iOS程序运行过程中,会创建无数个池子。这些池子都是以栈结构存在(先进后出)

               ②  当一个对象调用autorelease方法时,会将这个对象放到栈顶的释放池

               6、自动释放池的创建方式

    @autoreleasepool
     {
        
     }

              7、代码举例

     1 void test()
     2 {
     3     @autoreleasepool
     4     {// { 开始代表创建了释放池
     5         
     6         // autorelease方法会返回对象本身
     7         // 调用完autorelease方法后,对象的计数器不变
     8         // autorelease会将对象放到一个自动释放池中
     9         // 当自动释放池被销毁时,会对池子里面的所有对象做一次release操作
    10         Person *p = [[[Person alloc] init] autorelease];
    11         
    12         p.age = 10;
    13         
    14         
    15         
    16         @autoreleasepool
    17         {
    18             // 1
    19             Person *p2 = [[[Person alloc] init] autorelease];
    20             p2.age = 10;
    21             
    22             
    23         }
    24         
    25         
    26         Person *p3 = [[[Person alloc] init] autorelease];
    27         
    28         
    29     } // } 结束代表销毁释放池
    30 }

      

  • 相关阅读:
    Delphi程序设计之惯用法
    有关ADO专题
    钓子程序代源
    delphi函数大集合
    2012暑期川西旅游之第四天(丹巴甲居藏寨小金达维日隆)
    主流F2.8标准变焦镜头信息
    2012暑期川西旅游之第一天(成都海螺沟)
    2012暑期川西旅游之第五天(四姑娘山之双桥沟)
    宾得最小饼干DA 40mm F2.8 Limited[转]
    主流F2.8标准变焦镜头信息
  • 原文地址:https://www.cnblogs.com/gaizuojia/p/4357563.html
Copyright © 2011-2022 走看看