zoukankan      html  css  js  c++  java
  • OC语言-05-OC语言-内存管理

    一、引用计数器

    1> 栈和堆

    1. ① 主要存储局部变量
      ② 内存自动回收
      
    2. ① 主要存储需要动态分配内存的变量
      ② 需要手动回收内存,是OC内存管理的对象
      

    2> 简介

    1. 作用

      ① 表示对象被引用的次数
      ② 通常由alloc、new、copy与release方法引发
      ③ 动态监测引用计数器的值,当值为0时回收对象所占的内存
      
    2. 使用注意

      ① 引用计数器一个NSUInteger类型的变量,占用4字节内存
      ② 在对象被创建的时候引用计数器的值被初始化为1
      ③ 每个使引用计数器加1的操作,都有一个引用计数器减1的操作与之
        对应
      

    3> 基本概念

    1. 僵尸对象

      ① 所占用的内存已经被回收的对象
      ② 僵尸对象不能再被使用
      
    2. 野指针

      ① 指向僵尸对象的指针
      ② OC中引用野指针会报错,错误信息:EXC_DAB_ACCESS
      
    3. 空指针

      ① 没有指向任何内存地址的指针
      ② 空指针的值通常为nil、NULL或0
      ③ 通常在创建指针时将其初始化,避免其指向不确定的内存
      ④ 在对象被销毁后,通常要将指向对象的指针赋值为nil,避免产生野
        指针
      

    4> 基本方法

    1. retain

      ① 使引用计数器加1
      ② alloc、new、copy等方法会自动调用retain方法
      ③ 每个retain方法都必须对应一个release方法
      ④ 返回值为对象本身
      
    2. release

      ① 使引用计数器减1
      ② 没有返回值
      ③ 用空指针调用release方法不会报错
      ④ 不是经过alloc方法创建的对象,不需要执行release操作
      
    3. dealloc

      ① 在对象被销毁时调用
      ② 通常需要重写dealloc方法
      ③ 重写dealloc方法时,必须在最后调用父类的dealloc方法
      ④ @property不会影响dealloc方法,只会影响色图特人和getter
      

    二、多对象内存管理

    1> 基本使用

    • 当拥有某个对象时,就对该对象执行retain操作
    • 当抛弃某个对象时,就对该对象执行release操作
    • 谁执行retain操作,谁就执行release操作

    2> set方法的内存管理

    1. 基本使用

      ① 当set方法的参数是OC对象时,通常要在set方法内实现内存管理
      ② 当参数与成员变量不一样时,才对成员变量执行release操作,对
        参数执行retain
      
    2. set方法的代码规范

      ① 基本数据类型:直接赋值
      ② OC对象类型
      	1)先判断是不是新对象
      	2)若是,对就对象执行一次release操作,对新对象执行一次retain
      	  操作
      	3)否则,不执行操作
      
    3. dealloc方法的代码规范

      ① 对self拥有的所有对象执行一次release操作
      ② 一定要调用父类的dealloc方法,且放在最后
      ③ 在ARC环境下重写dealloc方法不能调用父类的dealloc方法
      

    3> @property对内存的影响

    1. 基本使用

      ① 为成员变量生成setter和getter
      ② 默认生成的setter执行的是直接赋值,不涉及内从管理
      ③ 若setter的参数是OC对象,需要设置@property的参数,使其生成
        内存管理代码
      
    2. @property的参数

      ① 内存管理相关参数
      	1)retain:release旧对象,retain新对象(适用于OC对象类型)
      	2)assign:直接赋值(默认,适用于非OC对象)
      	3)copy:release旧对象,copy新对象
      	
      ② 控制成员变量属性的参数
      	1)readwrite:同时生成setter和getter的声明、实现
      	2)readonly:只会生成getter的声明、实现
      	
      ③ 多线程管理相关参数
      	1)nonatomic:生成setter方法时不加线程管理代码,性能高
      	  (一般用这个)
      	2)atomic:生成setter方法时加上线程管理代码,性能低(默认)
      	
      ④ 指定setter和getter名称的参数
      	1)通过setter指定生成的set方法的名称,通过getter指定生成的
      	  get方法的名称
      	2)不影响点语法的使用,点语法在使用时先转换为对应的set或get
      	  方法
      	3)通常当get方法的返回值为BOOL类型数据时,对get方法使用,
      	  set方法几乎不用
      

    4> 循环包含与循环引用

    1. 循环包含

      ① 但两个类的声明文件循环包含时,通常要在一个文件中用@class
        声明另一个类
      ② 使用规范
      	1)在.h文件中用@class声明类
      	2)在.m文件中用#import包含类的声明文件
      
    2. 循环引用

      ① 当两个OC类循环引用时,会产生内存管理问题
      ② 解决方法
      	1)在一个类的声明中,指定@property的内存管理参数为retain
      	2)在另一个类的生命中,指定@property的内存管理参数为release
      

    三、autorelease

    1> 基本使用

    1. 作用

      ① 将调用该方法的对象放进自动释放池,当池子销毁时,对池子内所有
        的对象执行一次release操作
      ② 通常在对象创建时调用,放回对象本身
      
    2. 自动释放池的创建方式

      ① 通过@autoreleasepool{}创建
      ② 通过NSAutoreleasePool类创建
      

    2> 使用注意

    • 自动释放池的创建和释放遵循栈规则
    • 调用autorelease方法不会对引用计数器产生影响
    • autorelease方法延迟了对象的释放时间,占用内存较大的对象不要使用
    • 一个对象不能多次调用autorelease方法
    • 一个对象不能同时使用autorelease方法和release方法

    3> 常见应用

    • 快速创建一个自动释放池内的对象

       ① 通常设计一个类方法,快速创建一个自动释放池内的对象
       ② 方法名通常以类名开头
       ③ 创建时要使用self调用alloc、init与autorelease方法,不要使用类名
      

    四、ARC

    1> 基本使用

    1. 强指针与弱指针

      ① 强指针
      	1)通过__strong声明的指针
      	2)所有的指针默认都是强指针
      ② 弱指针
      	1)通过__weak声明的指针
      	2)当弱指针指向的对象被释放,弱指针将被清空
      
    2. 判断准则

      只要没有强指针指向对象,对象就会被释放
      

    2> @property的strong和weak参数

    • strong参数相当于retain参数
    • weak参数相当于assign参数

    3> 循环引用的解决方法

    • 将@property一端的参数指定为strong
    • 将@property另一端的参数指定为weak

    五、示例(多文件)

    /*
     1.创建一个Person类和一个Dog类,Person类与Dog类是相互用有关系
     2.重写Person类与Dog类的dealloc方法
     3.重写Person类的set方法,实现内存管理代码
     4.自定义Person类构造方法,用于快速创建一个自动释放池内的Person对象
     */
     
     
    /*****main.m文件******/
    #import <Foundation/Foundation.h>
    //包含Person类的声明文件
    #import "Person.h"
    //包含Dog类的声明文件
    #import "Dog.h"
    
    int main()
    {
        //创建自动释放池
        @autoreleasepool {
            
            //创建Dog对象,并加入到自动释放池中
            Dog *d = [[[Dog alloc] init] autorelease];
            /*通过调用类方法快速创建一个Person类型的自动释放池对象
            并用Dog初始化新创建的对象的成员变量*/
            Person *p = [Person personWithDog:d];
            
            //将指针清空
            p = nil;
            
        }
        return 0;
    }
    
    
    /*****Person.h文件******/
    #import <Foundation/Foundation.h>
    
    //声明Dog是一个类,Dog.h文件用#import指令
    @class Dog;
    
    @interface Person : NSObject
    /*通过@property生成dog属性的getter和setter
     并使用参数retain,Dog.h使用assign参数*/
    @property (nonatomic, retain) Dog *dog;
    
    /*自定义方法,快速创建一个Person类型的自动释放池对象,
    并用Dog初始化新创建的对象的成员变量*/
    + (Person *)personWithDog:(Dog *)dog;
    @end
    
    
    /*****Person.m文件******/
    #import "Person.h"
    //使用@class声明的类,在实现文件中要用#import指令包含该类的头文件
    #import "Dog.h"
    
    @implementation Person
    + (id)personWithDog:(Dog *)dog
    {
        Person *p = [[[Person alloc] init] autorelease];
        //将dog赋值给新创建对象的成员变量
        p.dog = dog;
        return p;
    }
    
    //重写dealloc方法
    - (void)dealloc
    {
        NSLog(@"Person对象被释放");
        //释放person所拥有的属性
        [_dog release];
        //调用父类的dealloc方法
        [super dealloc];
    }
    @end
    
    
    /*****Dog.h文件******/
    #import <Foundation/Foundation.h>
    
    //包含Person.h头文件,Person.h文件用@class指令
    #import "Person.h"
    
    @interface Dog : NSObject
    /*通过@property生成person属性的getter和setter
     并使用参数retain,Person.h使用retain参数*/
    @property (nonatomic, assign) Person *person;
    @end
    
    
    /*****Dog.m文件******/
    #import "Dog.h"
    
    @implementation Dog
    //重写dealloc方法
    - (void)dealloc
    {
        NSLog(@"Dog对象被释放");
        //释放Dog所拥有的属性
        [_person release];
        //调用父类的dealloc方法
        [super dealloc];
    }
    @end
    
  • 相关阅读:
    HTTP 错误 500.21
    《21天学通C#》给多个变量赋值
    《21天学通C#》变量使用前需要声明和赋值,赋值后可以重新赋新的值
    《21天学通C#》课后习题:编写代码将你的名字打印到控制台
    《21天学通C#》数字前面补0
    《21天学通C#》将写的代码原封不动的在控制台显示
    《21天学通C#》Write和WriteLine的区别
    《21天学通C#生成XML文件
    《21天学通C#》嵌套循环,输出上三角形X。
    Scala之隐式转换implicit详解
  • 原文地址:https://www.cnblogs.com/theDesertIslandOutOfTheWorld/p/4728956.html
Copyright © 2011-2022 走看看