黑马程序员——Objective--C基础笔记之内存管理(一)------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
OC内存管理范围:
管理任何继承NSObject的对象,对其他的数据类型无效。
本质原因是因为对象和其他数据了警在系统中的存储空间不一样,其他局部变量主要存放在栈中,而对象存储于堆中,当代码块结束时,这个代码中设计所有局部变量会被回收,指向对象的指针也会被回收,此时对象已经没有指针指向,但依然存在于内存中,造成泄漏。
内存管理原理及分类
1)对象的所有权饮用计数器
对象所有权的概念
任何对象都可能拥有一个或多个所有者,只要一个对象还拥有一个所有者它就会继续存在。
任何自己创建的对象都归自己所有,可以使用名字以“alloc”或“new”开头或名字中包含“copy”的方法创建对象, 可以使用retain来获得一个对象的所有权。
2)对象的引用计数器(retaincount)
每个oc对象都有自己的引用计数器,是一个整数表示对象被引用次数,即现在有多少东西在使用这个对象,对象 刚被创建时,默认计数器值为1,当计数器的值变为0时,则对象销毁。
*在每个oc对象内部,都专门有8个字节的存储空间来存储引用计数器。
3)引用计数器的作用
引用计数器是判断对象是否要回收的依据(存在一种例外:对象值为nil时,引用计数器为0,但不回收空间)就是 计数器是否为0,若不为0则存在。
4)引用计数器的操作
给对象发送消息,尽享相应的计数器操作
retain消息 :使计数器+1,该方法返回对象本身
release消息 :使计数器-1(并不代表释放对象)
retaincount消息:获得当前的引用计数器值(%ld,%tu)
5)对象的销毁
当一个对象的引用计数器为0,那么它将销毁,其占用的内存呗系统回收,当对象呗销毁时,系统会自动向对象发送一条delloc消息,一般会重写dealloc方法,在这里释放相关的资源,dealloc就向“临终遗言”一旦重写了dealloc方法 就必须调用[super dealloc],并且在代码块最后调用(不能直接调用)。
oc内存管理分类
object-c提供了三种内存管理方式:
Mannul Reference Counting MRC 手动内存管理
automatoic reference counting ARC 自动内存管理
garbage colletion(垃圾回收) ios不支持垃圾回收
需理解MRC,但实际使用尽量用ARC
如何把arc
1 口诀。
1) 谁创建,谁释放。如果你通过alloc、new或copy来创建一个对象,那么你必须调用release或autorelease。换句话说,不是你创建的,就不用你去释放。
2) 除了alloc、new或copy之外的方法创建的对象都被声明了autorelease。
3) 谁retain,谁release。只要你调用了retain,无论这个对象是如何生成的,你都要调用release。有时候你的代码中明明没有retain,可是系统会在默认实现中加入retain。
注意:对象被释放后不能访问它的引用计数器,如果访问的话是野指针访问会造成系统崩溃。
3.重写dealloc方法
1).对象被销毁的时候,会默认调用dealloc方法
2).dealloc方法书写规范,要先释放自己的对象空间,在释放父类的空间
3).注意:dealloc方法不用手动去调用,系统会根据引用计数器的值自动调用
空指针,野指针,僵尸对象
空指针:没有任何东西的指针(存储的东西是nil, Nall0)
给空指针发送消息不会报错
野指针:指向僵尸对象(不可用内存)的指针,给野指针发送消息会报错
错误:EXC_BAD_ACCECC:访问一块坏的内存(已经被回收,已经不可用的内存)
@property参数
1) property的语法格式:
@property (参数1,参数2)类型名字;
这里的参数,主要有以下三种:
setter/getter方法(assign/retain/copy)
读写属性(readwrite/readonly)
atomicity(nonatomic)
三种使用方式
assign/retain/copy 代表赋值的方式。
readonly关键字代表setter不会被生成, 所以它不可以和 copy/retain/assign组合使用。
atomicity的默认值是atomic,读取函数为原子操作。
1.2.1 copy/reain/assign 在其中选择一个来确定属性的setter如何处理这个属性。NSObject对象采用这个中方式。
1.2.2 一些特别的Object比如NSSstring使用copy。
1.2.3 assign关键字代表setter直接赋值,而不是复制或者保留它。适用于基本数据类型,比如NSInteger和CGFloat,或者你并不直接拥有的类型,比如delegates。
set方法处理:
1).assign 直接赋值,适用于非oc对象,默认
例:@property(nonatomic, assign) int age;
2).retain 先release旧值,再retain新值
例:@property (nonatomic, retain) NSString *name;
3).copy分为浅复制和深复制 先release原来的值,再copy新值
4.set和get的方法名称,主要用于布尔类型。因为返回布尔类型的方法名一般以is开头,修改名称一般用在布尔类型中的getter。
1).替换set方法的名称:@property (nonatomic, setter = isVip:)
[p setVip:YES]; -------->[p isVip=YES];
2).替换get方法的名称:@property(nonatomic,getter=isVip:)
[p isVIP:YES];
@class的使用
1.格式:@class 类名
2.@class XXX 含义:告诉编译器,XXX是一个类,至于类有哪些方法和属性,此处不去检查
好处:如果XXX文件内容发生改变,而不需要重写编译
3.@class使用注意:
1). .h @class XX;
2). .m #import "XX.h"
@class的特殊用法可以解决循环引用问题
4.#import 和@class的区别
#import会包含引用类的所有信息(内容),包括引用类的属性和方法
@class仅仅是告诉编译器有这么一个类,具体类里面有什么信息,完全不知道
效率上的区别
如果有上百个文件都#import了同一个文件或者这些文件依次被#import,那么一旦开始的头文件有改动,后面引用了这个头文件的类都要重新编译,编译效率非常低,使用@class就不会出现这种问题。
5.循环retain会导致两个对象都会内存泄漏