黑马程序员-iOS基础-Objective-C基础(六)内存管理

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

黑马程序员-iOS基础-Objective-C基础(六)内存管理

一、内存管理的必要性

移动设备内存空间极其有限

app占用内存较多时,系统会发出内存警告,必须回收一些不需要再使用的内存

二、内存管理的范围

 任何继承了NSObject的对象

 对其他基本数据类型、struct、enum等无效

三、引用计数器

1.对象的基本结构

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

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

 当引用计数器=0时会被系统回收

当对象刚刚被创建时,引用计数器=1

2.引用计数器的作用

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

 当一个对象的引用计数器值为0时,对象占用的内存就会被系统回收。

换句话说,如果对象的计数器不为0,那么在整个程序运行过程,它占用的内存就不可能被回收,除非整个程序已经退出

3.引用计数器的操作

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

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

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

 有一个alloc,就要有一个release

有一个retain,就要有一个release

4.对象的销毁

 当一个对象的引用计数器值为0时,那么它将被销毁,其占用的内存被系统回收

 当一个对象被销毁时,系统会自动向对象发送一条dealloc消息

 一般会重写dealloc方法,在这里释放相关资源,dealloc就像对象的遗言

 一旦重写了dealloc方法,就必须调用[super dealloc],并且放在最后面调用

 不要直接调用dealloc方法

 一旦对象被回收了,它占用的内存就不再可用,坚持使用会导致程序崩溃(野指针错误)

5.要点

 5.1.方法的基本使用

    retain:计数器+1

    release:计数器-1

    retainCount:返回当前计数值

    dealloc

    当对象要被回收的时候就会调用

    一定要调用[super dealloc],并且要放在最后面

 5.2.概念

    僵尸对象:   所占用内存已经被回收的对象,不能再使用

    野指针:   指向僵尸对象(不可用内存)的指针,给野指针发消息会报错

    EXC_BAD_ACCESS     访问一块坏的内存(已经被回收,不可用的内存)

    空指针   没有指向任何东西的指针(存储的是nil,NULL,0)

    给空指针发消息不会报错

 5.3.retain方法会返回对象本身

练习:

//仅实现部分
#import <Foundation/Foundation.h>
#import "Person.h"

@implementation Person

//当一个Person对象被回收,就会自动调用这个方法
- (void)dealloc
{
	NSLog(@"Person对象被回收");

	//super dealloc一定要调用,而且放在最后面
	[super dealloc];
}

@end

int main(int argc, char const *argv[])
{
	// 1
	Person *p = [[Person alloc] init];
	NSUInteger c = [p retainCount];
	NSLog(@"计数器:%ld", c);

	// 2 retain方法返回的是对象本身
	[p retain];

	// 1
	[p release];
	// 0 野指针 :指向僵尸对象(不可用内存)的指针
	[p release];

	// -[Person setAge:] message sent to deallocated instance xxxxxx
	// 给已经释放的对象发送了一条-setAge:消息
	p.age = 10;

	//指针p变成空指针
	p = nil;//如果这一行不写会发生野指针错误,因为对象已经不可访问

	//EXC_BAD_ACCESS:访问一块坏的内存(已经被回收,不可用的内存)
	//野指针错误
	[p release];

	[nil release];//OC不存在空指针错误,不会报错,仅仅会报警告

	return 0;
}


四、多对象内存管理

 分析QQ堂游戏结论

  只要想用这个对象,就让对象的计数器+1

  当不再使用这个对象时,就让对象的计数器-1

 原则

  谁创建,谁release

如果你通过alloc、new或[mutable]copy来创建一个对象,那么你必须调用release或autorelease;换句话说,不是你创建的,就不用你去[auto]release

  谁retain,谁release

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

  想使用/占用某个对象,就应该让对象的计数器+1(对象做一次retain操作)

  不想使用/占用某个对象,就应该让对象的计数器-1(对象做一次release操作)

 总结

  有始有终,有加就有减

  曾经让对象的计数器+1,就必须在最后让对象计数器-1

五、set方法内存管理

   基本数据类型不需要管理内存,只需要管理对象

   当对新对象进行retain操作时,应该对旧对象进行release操作,并且判断传入对象和当前对象是否一样 

5.1.内存管理代码规范

    1.只要调用了alloc,就必须有release(autorelease)如果对象不是用alloc生成的,就不需要release

    2.set方法的代码规范

           基本数据类型,直接赋值

- (void)setAge:(int)age
{
	_age = age;
}

           OC对象类型

- (void)setCar:(Car *)car
{
	// 1.判断是不是新传进来的对象
	if( car != _car )
	{
		//是新对象,释放老对象
		[_car release];
		//对新对象进行retain操作
		_car = [car retain];
	}
}

    3.dealloc方法的代码规范

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

           对self(当前对象)所拥有的其他对象做一次release

- (void)dealloc
{
	[_car release];
	NSLog(@"xxxxx");
	[super dealloc];
}

5.2 @property的内存管理

 @property (retain) 类名 *对象名;

       retain:在生成的set方法里面,release旧值,retain新值

       @property (retain) Book *book;

       只影响set/get方法

 -dealloc方法中完成对象释放即可

 总结

  1.内存管理相关的参数

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

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

   copy:release旧值,copy新值

  2.是否要生成set方法

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

   readwrite:可读可写(默认),同时生成getter和setter的声明和实现

  3.多线程管理

   nonatomic:性能高,一般用这个

   atomic:性能低(默认)

  4.setter和getter方法的名称

   getter = xxx

   setter = xxx:

练习:

@implementation Person

- (void)setAge:(int)age
{
	_age = age;
}

- (void)setCar:(Car *)car
{
	// 1.判断是不是新传进来的对象
	if( car != _car )
	{
		//是新对象,释放老对象
		[_car release];
		//对新对象进行retain操作
		_car = [car retain];
	}
}

- (void)dealloc
{
	[_car release];
	NSLog(@"xxxxx");
	[super dealloc];
}

@end


六、@class

当有类A和类B时,如果类A需要import类B的声明,类B也需要import类A的声明时,不可以同时用#import导入

都应该使用@class,作用为告诉编译器,这是一个类,但这没有将另一个类的声明拷贝到当前类中

规范:

在声明部分用@class 类

在实现部分用#import .h头文件

总结:

 1.作用:告诉编译器某个名称是一个类

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

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

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

七、循环retain

 两端循环引用的解决方案:  一端用retain,  另一端用assign

八、autorelease(非自动释放,实际是半自动释放)

8.1 建议格式

@autoreleasepool
{
     Person *p = [[[Person alloc] init] autorelease];
}

8.2 总结

 基本用法

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

  当自动释放池被销毁时,会对池中的所有对象做一次release操作

  会返回对象本身

  调用完autorelease方法后,对象的计数器不变

 好处

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

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

 注意点

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

  当对占用内存比较小的对象时,可以考虑使用autorelease

  autorelease不能精确控制释放的时间,实际编程应多使用release

 错误写法

  1.alloc之后调用了autorelease,又调用了release

  2.连续调用多次autorelease

 自动释放池@autoreleasepool

  在iOS程序运行过程中,会创建无数个池子,这些池子都是以栈结构存在,先进后出

  当一个对象调用autorelease方法时,会将对象放到栈顶的自动释放池中

九、内存管理总结

 9.1 计数器的基本操作

  retain

  release

  retainCount

 9.2 set方法的内存管理

  set方法实现

  dealloc方法实现,不要直接调用

 9.3 @property参数

  OC对象类型

  非OC对象类型(int\float\enum\struct)

  被retain过的属性,必须在dealloc中release属性

 9.4 autorelease

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

  开发中经常会提高一些类方法快速创建一个已经autorelease过的对象,创建对象时不要用类名,一般用self

十、ARC

 创建项目时勾选Use Automatic Reference Counting

 基本原理:ARC的判断准则

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

   指针分2种

    强指针;默认情况下所有指针都是强指针 __strong

    弱指针:__weak

     错误写法

__weak Person *p = [[Person alloc] init];
//生成对象就被销毁

  当弱指针所指对象被销毁时,编译器自动清空弱指针

 @property的strong和weak:  ARC中retain换成strong

@property (nonatomic, strong) Dog *dog;

 总结

  1.不允许release、retain、retainCount

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

  3.@property的参数

   strong:成员变量是强指针,相当于原来的retain,OC对象类型

   weak:成员变量是弱指针,相当于原来的assign,OC对象类型

   assign:适用于非OC对象类型

  4.以前的retain改成strong

 Xcode的ARC转换功能:Edit-Refactor-Covert to Objective-C ARC

 在ARC项目内某个文件不要使用ARC:项目-Build Phases-Compile Sources-在对应文件位置输入“-fno-objc-arc”

 在非ARC项目内使某个文件使用ARC:项目-Build Phases-Compile Sources-在对应文件位置输入“-f-objc-arc”

 使用注意:  两端循环引用的解决方案

   ARC:一个使用strong,另一个使用weak

   非ARC:一个用retain,一个用assign

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值