zoukankan      html  css  js  c++  java
  • IOS开发学习笔记013-内存管理

     

    内存管理

      1、基本知识

      2、关闭ARC机制

      3、@property

      4、循环引用

      5、自动释放池 

      6、内存管理总结

    一、基本知识

    内存的分类

      栈:局部变量

      堆:动态申请的对象,变量等

      全局(静态):static 变量,const变量,全局变量等

    引用计数器

        每个OC对象都有自己的引用计数器,是一个整数,表示“对象被引用的次数”,即有多少人正在使用这个OC对象

      每个OC对象内部专门有4个字节的存储空间来存储引用计数器

     作用

      当使用alloc、new或者copy创建一个新对象时,新对象的引用计数器默认就是1

      当一个对象的引用计数器值为0时,对象占用的内存就会被系统回收。换句话说,如果对象的计数器不为0,那么在整个程序运行过程,

    它占用的内存就不可能被回收,除非整个程序已经退出。

    引用计数器的操作

      1、给对象发送一条retain消息,可以使引用计数器值+1(retain方法返回对象本身)

      2、给对象发送一条release消息,可以使引用计数器值-1

      3、可以给对象发送retainCount消息获得当前的引用计数器值

    总结:有始有终,有加有减。

     

    二、关闭ARC机制

    如果要自己调用release等函数,需要关闭ARC功能,关闭方法参考

    http://jingyan.baidu.com/article/358570f67babbcce4724fcd8.html 

    管理方式set方法加1,dealloc 减1

    1、想使用某个对象,就应该让对象的计数器加1(retain)

    2、不想再使用某个对象时,就应该让对象的计数器减1 (release)

    2、谁retain谁release,谁alloc谁release

    内存管理规范:

    1、只要调用alloc必须有release,如果不是alloc那就不需要release

    2、set 方法

      基本数据类型直接赋值  

      OC对象类型。

      先判断是不是同一个对象 if(car != _car)。

      然后对旧对象release,对新车进行一次retain操作。

    3、dealloc

      一定要调用[super dealloc],而且放到最后边

      一定要当前对象release一次

     三、@property 

    @property  // 默认是赋值,retain 参数实现内存管理

    @property int age; // 默认是赋值
    @property(retain) Book * book; // retain 参数实现内存管理

    内存管理总结:

    1、内存管理的相关参数

      retain  :release旧值,retain新值

      assign  :直接赋值,默认就是这个,适用于非OC对象类型

      copy   :release旧值,copy新值

      retain是指针拷贝,copy是内容拷贝。

    2、是否要生成set方法

      @property (readonly) int age; // 只读,只生成getter方法

      @property (readwrite) int name; // 读写,默认是读写

    3、多线程管理

      nonautomic   : 性能高,

      automic     : 性能低(默认)

      @property  (nonautomic , assign) int age; // 以后这样写,默认的assign也要写出来,这样比较明显

    4、setter和getter方法的名称

      @property  (setter = myAge:) int age; // setter = set方法名 ,自定义setter方法名,不要忘记冒号

      @property  (getter = getAge) int age; // getter = get方法名 ,自定义getter方法名

      @property  (getter = isRich) BOOL rich; // 一般这个会用在BOOL类型的变量声明,getter方法名以is开头

    四、循环引用

    类A引用类B,类B引用类A。

    解决方法:  @class A;//  仅仅告诉编译器A是一个类

    在类引用前,在声明文件里使用关键字@class A;

    @class 和#import区别

      1、#import方式会包含被引用类的所有信息,包括被引用类的变量和方法;@class方式只是告诉编译器在A.h文件中 B *b 只是类的声明,具体这个类里有什么信息,这里不需要知道,等实现文件中真正要用到时,才会真正去查看B类中信息

      2、如果有上百个头文件都#import了同一个文件,或者这些文件依次被#improt,那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,这样的效率也是可想而知的,而相对来 讲,使用@class方式就不会出现这种问题了

      3、在.m实现文件中,如果需要引用到被引用类的实体变量或者方法时,还需要使用#import方式引入被引用类

     

    代码示例

    1 #import <Foundation/Foundation.h>
    2 @class Card; // 引用类声明
    3 @interface Person : NSObject
    4 
    5 @property (nonatomic, retain) Card *card;
    6 
    7 @end
     1 #import "Person.h"
     2 #import "Card.h" // 包含头文件
     3 @implementation Person
     4 
     5 - (void)dealloc
     6 {
     7     //[_card release];
     8     NSLog(@"card dealloc");
     9     [super dealloc];
    10 }
    11 @end
    1 #import <Foundation/Foundation.h>
    2 @class Person; // 引用类声明
    3 
    4 @interface Card : NSObject
    5 
    6 @property (nonatomic, retain) Person *person;
    7 
    8 @end
     1 #import "Card.h"
     2 #import "Person.h" // 引用头文件
     3 @implementation Card
     4 - (void)dealloc
     5 {
     6     [_person release];
     7     NSLog(@"person dealloc");
     8     [super dealloc];
     9 }
    10 @end

    main函数

     1  int main()
     2 {  
     3     Person *p = [[Person alloc] init];
     4     Card *c = [[Card alloc] init];
     5      //   这里就回出现循环retain现象,下面会解释解决方法
     6     p.card = c;
     7     c.person = p;
     8     
     9     // 实际上,这两个对象都没释放
    10     [p release];
    11     [c release];
    12     return 0;  
    13 }

    针对上面的问题,这里给出一个解决方法,如下:

    1 #import <Foundation/Foundation.h>
    2 @class Person; // 引用类声明
    3 
    4 @interface Card : NSObject
    5 
    6 // 避免循环retain导致对象不能正确释放,可以把其中一个的声明写为assign,这样就可以正常释放,这是一个特例
    7 @property (nonatomic, assign) Person *person;
    8 
    9 @end

    在开发中引用一个类的规范

     1、在.h文件中用@class来声明类

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

     3、 循环retain的解决方案

       一端用retain,一端用assign

    五、自动释放池

    autorelease 基本用法

      1、会将对象放到一个自动释放池中

      2、当对象释放池被销毁时,会自动释放里面的所有对象(release操作)

      3、会返回对象自身

      4、调用autorelease后,对象的计数器不变

    好处

      1、不用再关心对象释放的时间

      2、不用再关心什么时候调用release

    注意事项

      1、占用内存较大的对象不要随便使用autorelease

      2、占用内存较小的使用autorelease,没有太大影响

      3、autorelease和release一样,也是和alloc/new/copy一一对应

      4、自动释放池是以栈结构存储在内存中的,当调用一个autorelease时,会将对象放到栈顶

      5、系统自带的方法里面没有含有alloc、new、copy,说明返回的对象都是autorelease类型的

      6、开发中常常会提供一个快速生成一个返回autorelease类型的类方法

        创建对象不要直接用类名,要用self,这样子类调用也不会出错

      7、

     1 @autoreleasepool // 自动释放池
     2     {
     3         Person *p = [[[Person alloc] init] autorelease]; // autorelaese 方法返回对象本身,计数器并不会立即改变
     4         Card *c = [[[Card alloc] init] autorelease];
     5         
     6         p.card = c;
     7         c.person = p;
     8         
     9         @autoreleasepool // 可以嵌套
    10         {
    11             
    12             Person *p = [[[Person alloc] init] autorelease];
    13             Card *c = [[[Card alloc] init] autorelease];
    14             
    15             
    16             p.card = c;
    17             c.person = p;
    18             
    19             
    20         }
    21         
    22     }

     autorelease优化

    写一个类方法将autorelease封装起来

    1 // 类方法,返回对象自身,将autorelease封装起来
    2 + (id)person
    3 {
    4     return [[[Person alloc] init] autorelease]; // 直接返回对象
    5 }

    使用起来很方便

      Person *p = [Person person];

    字符串  默认就是autorelease

        NSString *str = @"dsfgsdfg"; // 默认就是autorelease

    内存管理总结

      计数器基本操作

        retain +1

        release -1

        retainCount 获得计数器

      set方法的内存管理

        - (void)setCar:(Car *)car

        {

          if(car != _car)

          {

            [_car relaease];

            _car = [car retain];  

          }

        }

      @property参数

        OC对象类型

        @property (nonatomic, retain) 类名 *属性名;

        @property (nonatomic, tetain) Car *car;

        retain过一定要在dealloc里进行release

        非OC类型那个

        @property (nonatomic, assign) 类型名 属性名;

        @property (nonatomic, assign) int age;

       autorelease

        系统自带的方法中,如果不包含alloc、new、copy,那么这些方法返回的都是autorelease过的

        开发中常常会提供一个快速生成一个返回autorelease的对象,创建对象不要直接用类名,要用self,这样子类调用也不会出错

    2015-04-18 今日如此,明日依旧。

  • 相关阅读:
    201671010439-词频统计软件项目报告
    201671010439温永琴 实验三作业互评与改进
    读构建之法提出的问题
    实验十四 团队项目评审&课程学习总结
    201671010441 徐浩杰 实验四 附加实验 项目互评
    201671010441 徐浩杰《英文文本统计分析》结对项目报告
    201671010441徐浩杰 词频统计软件项目报告
    201671010441 徐浩杰 实验三作业互评与改进报告
    实验一 通读教材后提问
    实验十四 团队项目评审&课程学习总结
  • 原文地址:https://www.cnblogs.com/songliquan/p/4435756.html
Copyright © 2011-2022 走看看