OC之内存管理(个人笔记)

来源:互联网 发布:淘宝双11购物券怎么用 编辑:程序博客网 时间:2024/06/02 06:40
/*
   1
)为什么要进行内存管理?
   
移动设备的内存有限
 
 
   2
)内存管理的范围
   
所有的继承了NSObject类的对象
 
   3
)内存管理的原理
 
      i
,对象的所有权
 
        
一个对象的所有者(拥有者)
 
      ii,
对象的引用计数器
 
         1
)一个变量,2)每个对象都有  38个字节
         4
)用来存储对象的所有者的个数
 
      iii.
对象引用计数器的作用
   
        
用来标识一个对象是否要销毁
         1
)如果引用计数器> 0    不能销毁
         2
)如果引用计数器== 0   销毁 (例外,对象为nil时候,计数器为0但是不销毁)
 
      iiii.
引用计数器的操作:
 
         1
给对象发送 reatin 消息  +1
         2
........ release       -1
         3) 
查看计数器的值 retainCount
 
    4)
对象销毁
 
       1
)如果对象被销毁,他的内存空间被系统回收
       2
)对象销毁之前,会有一个临终“dealloc方法(对象销毁的时候,系统自动的调用这个对象的dealloc方法)
       3
)对象销毁retainCount == 0
 
 
 
    5)
内存管理的分类:
 
       1
MRC手动内存管理
       2)ARC
自动内存管理
 */


  • 1.为什么基本数据类型可以放在中存储?对象类型却要放在堆中存储?
  • 基本数据类型:大小固定
  • 对象数据类型:大小不固定
  • 2.为什么内存管理只管理对象类型
  • 代码执行完毕后,“堆内存”不会自动销毁,而“栈”内存会自动弹栈(释放)。
 引用计数器:
  • 简单来说,可以理解为:引用计数器表示有多少人正在使用这个对象
  • 当没有任何人使用这个对象时,系统才会回收这个对象,也就是说
  • 当对象的引用计数器为0,  对象占用的内存就会被系统回收
  • 如果对象的计数器不为0,那么在整个程序运行过程,它占用的内存就不可能被回(除非整个程序已经退出)
  • 任何一个对象,刚生下来的时候,引用计数器都为1。对象一旦创建好,默认引用计数器就是1
  • 当使用allocnew或者copy创建一个对象时,对象的引用计数器默认就是1
  • 要想管理对象占用的内存,就得学会操作对象的引用计数器
  • 引用计数器的常见操作
  • 给对象发送一条retain消息,可以使引用计数器值+1retain方法返回对象本身
  • 给对象发送一条release消息,可以使引用计数器值-1
  • 给对象发送retainCount消息,可以当前的引用计数器值(通过%ld输出查看)
  • 需要注意的是:release并不代表销毁\回收对象,仅仅是计数器-1
  • 注意:我们只能通过操作对象计数器,间接控制对象的释放与否
关闭ARC
  • 选中项目->选中All->搜索 AutomaticReference Counting
  • 修改为No
dealloc
  • 当一个对象的引用计数器值为0
  • 这个对象即将被销毁,其占用的内存被系统回
  • 系统会自动给对象发送一条dealloc消息

(因此,dealloc方法有没有被调用,就可以判断出对象是否被销毁)

  • dealloc方法的重写
  • 一般会重写dealloc方法,在这里释放相关资源,dealloc就是对象的遗言
  • 一旦重写了dealloc方法,就必须调用[superdealloc],并且放在最后面

  • 使用注意
  • 不能直接调用dealloc方法
  • 一旦对象被回收了,占用的内存就不再可用,坚持使用会导致程序崩溃(野指针错误为了防止调用出错,可以将野指针指向nil0)。
  • 僵尸对象
  • 已经被销毁的对象(不能再使用的对象)
  • 野指针
  • 指向僵尸对象(不可用内存)的指针
  • 给野指针发消息会报EXC_BAD_ACCESS/EXC_BREAKPOINT错误(message sent to deallocatedinstance 0x100100350)
  • 空指针
  • 没有指向存储空间的指针(里面存的是nil,也就是0)
  • 给空指针发消息是没有任何反应的,不会提示出错!
  • 为了避免野指针错误的常见办法
  • 在对象被销毁之后,将指向对象的指针变为空指针(p=nil)
  • 苹果官方规定的内存管理原则
  • 谁创建谁release: 如果你通过allocnewcopymutableCopy来创建一个对象,那么你必须调用releaseautorelease
  • retainrelease:只要你调用了retain就必须调用一次release
  • 总结一下就是
  • 有加就有减
  • 曾经让对象的计数器+1,就必须在最后让对象计数器-1
  • 在自己负责的区域内(某个方法范围内、某个对象内等。):有+,就得有-
@property 参数
  • 控制set方法的内存管理
  • retain release旧值,retain新值(用于OC对象,要配合nonatomic使用。
  • assign: 直接赋值,不做任何内存管理(默认,用于非OC对象类型)
  • copy  release旧值,copy新值(一般用于NSString*
  • 控制需不需生成set方法
  • readwrite:同时生成set方法和get方法(默认
  • readonly :只会生成get方法
  • 多线管理
  • atomic   :性能低(默认
  • nonatomic:性能为iOS系统开发软件建议使用,为mac开发软件可以使用atomic
  • 控制set方法和get方法的名称
  • setter: 设置set方法的名称,一定有个冒号:
  • getter: 设置get方法的名称
  • @property (nonatomic, retain, setter =setUserName:, getter =getUserName)NSString *name;
  • 一般只有BOOL类型的属性的get方法才会使用getter修改一下方法名为isXxxx,其他很少用的
  • @property (nonatomic, assign) BOOL rich;
  • @property (nonatomic, assign, getter =isRich) BOOL rich;
@class

遇到的问题:

1.要在某个类的头文件中使用另外一个类型,必须通过#import来引入另外一个类型的头文件这样一旦被引用的头文件被修改,所有引用该头文件的文件都得修改重新编译,造成低效率

3.循环引用(循环依赖)问题

作用

  • 可以简单地引用一个

简单使用

  • @classDog;
  • 仅仅是告诉编译器:Dog是一个类;并不会包含Dog这个类的所有内容

具体使用

  • .h文件中使用@class引用一个类
  • .m文件中使用#import包含这个类的.h文件
  • 注意:继承某个类的时候不能使用@class,必须#import
@class 和 #import 

作用上的区别

  • #import会包含引用类的所有信息(内容),包括引用类的变量和方法
  • @class仅仅是告诉编译器有这么一个类,具体这个类里有什么信,完全不知

效率上的区别

  • 如果有上百个头文件都#import了同一个文件,或者这些文件又依次被#import,那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,编译效率非常低
  • 相对来讲,使用@class方式就不会出现这种问题了
0 0
原创粉丝点击