黑马程序员---Objective-C学习笔记之二

时间:2021-04-17 00:19:11
------- android培训java培训、期待与您交流! ----------

内存管理

为什么要进行内存管理?

1>硬件条件的限制:移动设备的内存有限,所以每个App所占的内存也是有限制的,当App占用较多内存时,系统会发出警告,严重的时候引起“闪退”。

2>本质原因在于:存储空间不同,局部变量一般存储在栈中,对象一般存储在堆中,当栈中变量销毁后,对象内存已经无指向,就会内存泄露。

 

引用计数:

判断对象要不要回收的唯一标准,当计数器为0时,回收对象。

创建对象时,将它的引用次数设置为1,每一次必须保持该对象时,就发送一条retain 消息,使其引用次数加1。

[myFractionretain];

不再需要对象时,可以通过发送release 消息,使对象的引用次数减1。

[myFractionrelease];

想要获取对象当前的计数器值,可以通过发送retainCount消息

[myFractionretainCount];

 

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

 

对象的销毁:

当对象被销毁时,系统会自动想对象发送一条delloc消息,一般会重写delloc方法,在这里释放相关的资源。一旦重写了delloc方法就必须在最后调用[super delloc]。

 

一旦对象被回收了,那么他所占据的存储空间就不可用,指向对象的指针最好赋值为空,否则会引起野指针错误,后果不可预知。

 

野指针: 一个指向已经不存在的内存的指针。

僵尸对象:已经被回收的对象,或者说对象所对应的内存地址已经不可用的对象称为僵尸对象。过度释放会导致僵尸对象的产生。

空指针:没有指向任何东西的指针,给空指针发送消息不会报错。

 

内存管理的原则:

1>原则

       只要还有人在使用某个对象,那么这个对象就不会被回收;

       只要你想使用这个对象,那么久应该让这个对象的引用计数+1;

       当你不想使用这个对象时,应该让对象的引用计数-1。

2>谁创建,谁release

黑马程序员---Objective-C学习笔记之二

3>谁retain,谁release

       只要你调用了retain,无论这个对象如何生成的,你都要掉调用release。

4>有始有终,有加就应该有减。曾经让某个对象计数器+1,就应该让其在最后-1。

 

内存管理代码规范

1>只要调用了alloc,就必须有release(autorelease)

2>Set方法的代码规范

  1. 基本类型

  - (void) setAge : (int)age

  {

              _age = age;

  }

      

  2. OC对象类型

  - (void) setCar : (Car*)car

  {

              // 1.先判断是不是新传进来的对象

              if( car != _car)

              {

                     // 2.对就对象进行一次release

                     [_car release];    //若没有就对象,则没有影响

                     // 3.对新对象进行一次retain

                     _car = [_car retain];

              }     

  }

3>重写delloc方法的代码规范

  1. 一定要在最后调用[super delloc]

  2. 对self(当前)所拥有的对象做一release操作

  - (void) delloc

  {

              [_car release];

              [super release];

  } 

 

@property的参数:

1> 内存管理相关参数

Retain: 对对象release旧值,retain新值(适用于OC对象类型)

Assign: 直接赋值(默认,适用于非oc对象类型)

Copy: release旧值,copy新值

 

2> 是否要生成set方法(若为只读属性,则不生成)

Readonly: 只读,只会生成getter的声明和实现

Readwrite: 默认的,同时生成setter和getter的声明和实现

 

3> 多线程管理(苹果在一定程度上屏蔽了多线程操作)

Nonatomic: 高性能,一般使用这个

Atomic: 低性能

 

4> set和get方法的名称

修改set和get方法的名称,主要用于布尔类型。因为返回布尔类型的方法名一般以is开头,修改名称一般用在布尔类型中的getter。

@property(setter=setAbc,getter=isRich) BOOL rich;

BOOL b = p.isRich;// 调用

 

内存管理中的循环引用问题以及解决:

案例:每个人有一张身份证,每张身份证对应一个人,不能使用#import的方式相互包含,这就形成了循环引用。

@class 类名——解决循环引用问题,提高性能

@class仅仅告诉编译器,在进行编译的时候把后面的名字作为一个类来处理。

1> @class的作用:声明一个类,告诉编译器某个名称是一个类

2> 开发中引用一个类的规范

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

       2. 在.m文件中真正要使用到的时候,使用#import来包含类中的所有东西

3> 两端循环引用的解决方法

一端使用retain,一端使用assign(使用assign的在dealloc中也不用再release)

 

Autorelease:

1> 基本用法

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

  2. 当自动释放池被销毁时,会对池子里的所有对象做一次release

  3. 会返回对象本身

  4. 调用完autorelease方法后,对象的计数器不受影响(销毁时影响)

 

2> 好处

  1. 不需要再关心对象释放的时间

  2. 不需要再关心什么时候调用release

 

3> 使用注意

  1. 占用内存较大的对象,不要随便使用autorelease,应该使用release来精确控制

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

 

4> 错误写法

  1. 连续调用多次autorelease,释放池销毁时执行两次release

  2. Alloc之后调用了autorelease,之后又调用了release。

 

5> 自动释放池

  1. 在ios程序运行过程中,会创建无数个池子,这些池子都是以栈结构(先进后出)存在的。

  2. 当一个对象调用autorelease时,会将这个对象放到位于栈顶的释放池中。

 

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

  1. iOS5.0以前的创建方式

       NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];

       `````````````````

       [pool  release];//[pool drain];用于mac 

  2. iOS5.0以后

       @autoreleasepool

       {//开始代表创建自动释放池

       ·······

       }//结束代表销毁自动释放池

 

7> Autorelease注意

       1. 系统自带的方法中,如果不包含alloc new copy等,则这些方法返回的对象都是autorelease的,如[NSDate  date];

       2. 开发中经常会写一些类方法来快速创建一个autorelease对象,创建对象时不要直接使用类名,而是使用self

 

ARC内存管理机制:

 1> ARC的判断准则:

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

 2> 指针分类:

   1. 强指针:默认的情况下,所有的指针都是强指针,关键字strong

   2. 弱指针:_ _weak关键字修饰的指针

   声明一个弱指针如下:

   _ _weak Person *p;

ARC中,只要弱指针指向的对象不在了,就直接把弱指针做清空操作。

_ _weak Person *p=[[Person alloc]  init];//不合理,对象一创建出来就被释放掉,对象释放掉后,ARC把指针自动清零。

ARC中在property处不再使用retain,而是使用strong,在dealloc中不需要再[super dealloc]。

@property(nonatomic,strong)Dog *dog;// 意味着生成的成员变量_dog是一个强指针,相当于以前的retain。

如果换成是弱指针,则换成weak,不需要加_ _。

  3> ARC的特点总结:

  1. 不允许调用release,retain,retainCount 

  2. 不允许重写dealloc,但是不允许调用[super dealloc]

  3. @property的参数:

Strong:相当于原来的retain(适用于OC对象类型),成员变量是强指针

Weak:相当于原来的assign,(适用于oc对象类型),成员变量是弱指针

Assign:适用于非OC对象类型(基础类型)

 4> 补充

  让程序兼容ARC和非ARC部分。转变为非ARC  -fno-objc-arc  转变为ARC 的, -f-objc-arc 。

  ARC也需要考虑循环引用问题:一端使用retain,另一端使用assign。

提示:字符串是特殊的对象,但不需要使用release手动释放,这种字符串对象默认就是autorelease的,不用额外的去管内存。

 

内存管理规则摘要:

       1> 释放对象,可以释放其所占的内存,规则是:不再使用创建或者保持的对象时,就释放它们。

       2> 发送一条release 消息不一定销毁对象,只有引用计数变为0 时,才销毁这个对象。系统向对象发送一条dealloc 消息来释放它所占的内存。

       3> 自动释放池在释放池本身的时候自动释放池中的对象。系统向每个对象发送一条release 消息,对引用计数变为0 的对象发送一条dealloc 消息来释放它所占的内存。

       4> 若你的方法中不再需要一个对象时,但需要返回它,可发送一条autorelease 消息来加入自获得途径临时对象拥有对象alloc/new/copy 不再使用时释放对象在dealloc 方法中释放对象任何其他方法不需要执行任何操作获得对象时保留,在dealloc 方法中释放对象动释放池。

       5> 若使用alloc 或copy 方法(或使用allocWithZone:、copyWithZone:或mutableCopy 方法来直接创建对象,则由你负责释放它。每次retain 对象时,应该release 或autoreleas 它。

       6> 除了上以规则中提到的方法之外,不必费心地释放其他方法返回的对象,这不是你的责任。