ios oc基础加强视频-源码第01天01-内存管理_第1页
ios oc基础加强视频-源码第01天01-内存管理_第2页
ios oc基础加强视频-源码第01天01-内存管理_第3页
ios oc基础加强视频-源码第01天01-内存管理_第4页
ios oc基础加强视频-源码第01天01-内存管理_第5页
已阅读5页,还剩41页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

内存管理传智如意大师内存移动设备的内存极其有限,每个app所能占用的内存是有限制的

下列行为都会增加一个app的内存占用创建一个OC对象定义一个变量调用一个函数或者方法当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不需要再使用的内存空间。比如回收一些不需要使用的对象、变量等如果app占用内存过大系统可能会强制关闭app,造成闪退现象,影响用户体验内存管理如何回收那些不需要再使用的对象?那就得学会OC的内存管理所谓内存管理,就是对内存进行管理,涉及的操作有:分配内存:比如创建一个对象,会增加内存占用清除内存:比如销毁一个对象,能减小内存占用内存管理的管理范围任何继承了NSObject的对象

(所有的OC对象,对象类型)对其他非对象类型(基本数据类型)无效(int、char、float、double、struct、enum等)只有OC对象才需要进行内存管理的本质原因OC对象存放于堆里面非OC对象一般放在栈里面(栈内存会被系统自动回收)将下面的代码画内存图分析,说明堆、栈存储intmain(intargc,constchar*argv[]){inta=10;//栈

intb=20;//栈

Car*c=[[Caralloc]init];

//堆return0;}画图分析内存分配过程voidm1(intn,intm){intsum=n+m;Car*c=[[Caralloc]init];}intmain(){

//分析m1方法被调用的时候内存分配情况

m1(10,20);}举例NSString*s1=@”bob”;NSString*s2=@”嘉木样·洛桑久美·图丹却吉尼玛”;**说明:同样都是NSString*类型,但是占用的内存字节数确不相同。**说明:整型变量,无论保存0还是10000都是占用4个字节。要说明的问题1.为什么基本数据类型可以放在“栈”中存储?“对象类型”却要放在堆中存储?基本数据类型:大小固定对象数据类型:大小不固定2.为什么内存管理只管理“对象类型”?代码执行完毕后,“堆内存”不会自动销毁,而“栈”内存会自动弹栈(释放)。内存栈内存(非OC对象)堆内存(OC对象)a

=

10b

=

20地址:0xffc0Car对象计数器==1c

=

0xffc0堆和栈什么是引用计数器(ReferenceCounting)系统是如何判断

什么时候需要回收一个对象所占用的内存?根据对象的引用计数器什么是引用计数器每个OC对象都有自己的引用计数器它是一个整数(int类型)从字面上,可以理解为”对象被引用的次数”也可以理解为:它表示有多少人正在用这个对象OC对象4字节–引用计数器每个OC对象内部都有4个字节的存储空间来存放引用计数器引用计数器的作用简单来说,可以理解为:引用计数器表示有多少人正在使用这个对象当没有任何人使用这个对象时,系统才会回收这个对象,也就是说当对象的引用计数器为0时,对象占用的内存就会被系统回收如果对象的计数器不为0,那么在整个程序运行过程,它占用的内存就不可能被回收(除非整个程序已经退出)任何一个对象,刚生下来的时候,引用计数器都为1。(对象一旦创建好,默认引用计数器就是1)当使用alloc、new或者copy创建一个对象时,对象的引用计数器默认就是1引用计数器的操作要想管理对象占用的内存,就得学会操作对象的引用计数器引用计数器的常见操作给对象发送一条retain消息,

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

可以使引用计数器值-1给对象发送retainCount消息,可以获得当前的引用计数器值(通过%ld输出查看)需要注意的是:release并不代表销毁\回收对象,仅仅是计数器-1注意:我们只能通过操作对象计数器,间接控制对象的释放与否。关闭ARC选中项目->选中All

->搜索Automatic

Reference

Counting修改为No演示retain、release、retainCount使用1.写代码演示2.画图说明。3.如何证明对象被销毁了?重写dealloc方法。dealloc当一个对象的引用计数器值为0时这个对象即将被销毁,其占用的内存被系统回收系统会自动给对象发送一条dealloc消息(因此,从dealloc方法有没有被调用,就可以判断出对象是否被销毁)dealloc方法的重写一般会重写dealloc方法,在这里释放相关资源,

dealloc就是对象的遗言一旦重写了dealloc方法,就必须调用[super

dealloc],并且放在最后面调用使用注意不能直接调用dealloc方法一旦对象被回收了,

它占用的内存就不再可用,

坚持使用会导致程序崩溃(野指针错误)为了防止调用出错,可以将“野指针”指向nil(0)。

野指针\空指针\僵尸对象僵尸对象已经被销毁的对象(不能再使用的对象)野指针指向僵尸对象(不可用内存)的指针给野指针发消息会报EXC_BAD_ACCESS/EXC_BREAKPOINT错误(messagesenttodeallocatedinstance0x100100350)空指针没有指向存储空间的指针(里面存的是nil,也就是0)给空指针发消息是没有任何反应的,不会提示出错!为了避免野指针错误的常见办法在对象被销毁之后,将指向对象的指针变为空指针(p=nil)输出“野指针”与“指向僵尸对象的指针”地址通过NSLog(@”-----%p-----“,p1);输出对象的地址来查看,僵尸对象与nil对象的区别。nil对象表示不指向任何对象僵尸对象,表示指向了一个已经被释放的对象。关闭ARC功能(iOS5开始)要想手动调用retain、release等方法,就必须关闭ARC功能开启僵尸对象监控默认情况下,Xcode是不会管僵尸对象的,使用一块被释放的内存也不会报错。为了方便调试,应该开启僵尸对象监控多对象内存管理单个对象的内存管理,看起来非常简单如果对多个对象进行内存管理,并且对象之间是有联系的,那么管理就会变得比较复杂1.多个变量同时使用(指向)同一个对象2.多个对象之间互相有关联关系。其实,多个对象的管理思路跟很多游戏的房间管理差不多比如斗地主\

QQ堂总的来说,有这么几点管理规律只要还有人在用某个对象,那么这个对象就不会被回收只要你想用这个对象,就让对象的计数器+1当你不再使用这个对象时,就让对象的计数器-1示例代码:每次有新变量引用对象都要retain。用完都要releasePerson*p1=[[Personalloc]init];

[p1retain];Person*p2=p1;

[p1retain];Person*p3=p1;

//使用对象[p3release];[p2release];[p1release];问题1:这段代码是否有内存问题?通过dealloc验证问题2:如果把第一行与最后一行之间的所有retain、release都删除掉,那么行吗?(在p1

release后,p2、p3还需要使用的)**注意:手动内存管理的时候,每次赋值对象的时候需要手动retain,不用的时候需要手动release。Person拥有Car对象案例:结合画图演示!步骤:1.创建Person类、Car类,并重写每个类的dealloc方法。2.在Person类中,增加一个Car类型的属性。自己写get、set方法。3.在main函数中,创建Person、Car对象,然后将Car对象赋值给Person对象。最后Person对象release一次,Car对象release一次。提问:有没有内存问题?这样写合理吗?4.因为上面的代码没有进行内存管理,所以car只要release一次,所有其他地方都不能用了,这样做不合理。5.setCar方法中:增加一个retain重写dealloc方法:对car执行一次release换车了:重新赋值一个新car的时候,对旧car执行一次release重复换同样的车:判断如果不是同一个对象,然后再执行set赋值。演示重复赋值同一个对象Person拥有Car对象案例演示点:正常创建一个Person对象、Car对象进行内存管理让Person对象拥有Car对象进行内存管理关键点:如果在为属性赋值的时候不进行内存管理,那么在p对象释放前Car对象已经释放了。画图演示。set方法的内存管理set方法-(void)setCar:(Car*)car{

if(car!=_car){

//对当前正在使用的车(旧车)做一次release[_car

release];

//对新车做一次retain操作

_car=[carretain];}}dealloc方法的内存管理dealloc方法-(void)dealloc{

//当人不在了,代表不用车了

//对车做一次release操作[_car

release];

//

self.car

=

nil;[super

dealloc];}介绍:self.car=nil;这种写法。错误写法,学了autorelease后回来再看。下面代码都会引发内存泄露p.dog=[[Dog

alloc]init];[[Dog

alloc]init].weight=20.8;内存管理原则苹果官方规定的内存管理原则谁创建谁release

:

如果你通过alloc、new或copy、mutableCopy来创建一个对象,那么你必须调用release或autorelease谁retain谁release

:只要你调用了retain,就必须调用一次release总结一下就是有加就有减

曾经让对象的计数器+1,就必须在最后让对象计数器-1在自己负责的区域内(某个方法范围内、某个对象内等。):有+,就得有-。@property编写一个Person类、Car类、Dog类,并重写每一个类的dealloc方法。让Person类拥有car属性、dog属性,自己编写car属性与dog属性的get、set方法(复习内存管理代码)通过@property关键字自动生成内存管理代码@property参数控制set方法的内存管理retain

:release旧值,retain新值(用于OC对象),要配合nonatomic使用。assign

:直接赋值,不做任何内存管理(默认,用于非OC对象类型)copy

:release旧值,copy新值(一般用于NSString*)控制需不需生成set方法readwrite

:同时生成set方法和get方法(默认)readonly

:只会生成get方法多线程管理atomic

:性能低(默认)nonatomic

:性能高(为iOS系统开发软件建议使用,为mac开发软件可以使用atomic)@property参数控制set方法和get方法的名称setter

:设置set方法的名称,一定有个冒号:getter

:设置get方法的名称@property(nonatomic,retain,setter=setUserName:,getter=getUserName)NSString*name;一般只有BOOL类型的属性的get方法才会使用getter修改一下方法名为isXxxx,其他很少用的。@property(nonatomic,assign)BOOLrich;@property(nonatomic,assign,getter=isRich)BOOLrich;使用@property案例课上案例:电商app类分析作业:微博案例,使用@property生成内存管理代码。首先禁用ARC。@class遇到的问题:1.要在某个类的头文件中使用另外一个类型,必须通过#import来引入另外一个类型的头文件,这样一旦被引用的头文件被修改,所有引用该头文件的文件都得修改重新编译,造成低效率3.循环引用(循环依赖)问题作用可以简单地引用一个类简单使用@class

Dog;仅仅是告诉编译器:

Dog是一个类;并不会包含Dog这个类的所有内容具体使用在.h文件中使用@class引用一个类在.m文件中使用#import包含这个类的.h文件注意:继承某个类的时候不能使用@class,必须#import@class和#import作用上的区别#import会包含引用类的所有信息(内容),包括引用类的变量和方法@class仅仅是告诉编译器有这么一个类,

具体这个类里有什么信息,完全不知效率上的区别如果有上百个头文件都#import了同一个文件,或者这些文件又依次被#import,那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,编译效率非常低相对来讲,使用@class方式就不会出现这种问题了

@class其他使用场景对于循环依赖关系来说,比方A类引用B类,同时B类也引用A类这种嵌套包含的代码编译会报错

当使用@class在两个类相互声明,就不会出现编译报错#import"B.h"@interfaceA:NSObject{

B*_b;}@end#import“A.h"@interfaceB:NSObject{

A*_a;}@end@class

B;@interfaceA:NSObject{

B*_b;}@end@class

A;@interfaceB:NSObject{

A*_a;}@end循环retain(内存管理的问题,无法释放)循环retain的场景比如A对象retain了B对象,B对象retain了A对象循环retain的弊端这样会导致A对象和B对象永远无法释放循环retain的解决方案当两端互相引用时,应该一端用retain、一端用assign,使用了assign后,dealloc中就不需要release了。案例演示1.创建Person类、Dog类,并重写每个类型的dealloc方法2.在main函数中创建Person对象、Dog对象,查看对象释放情况。3.让Person对象拥有Dog(通过@property

+

retain实现),同时在dealloc中释放dog,再查看main函数中的对象释放情况。4.让Dog对象拥有Person对象(通过@property

+

retain实现),同时在dealloc中释放person,再查看main函数中的对象释放情况。autorelease基本编程模型1.创建对象池2.把要自动release的对象放到对象池中3.当对象池释放的时候对该池子中的所有对象做一次release。autorelease简介autorelease方法的基本作用给对象发送一条autorelease消息,会将对象放到一个自动释放池中当自动释放池被销毁时,会对池子里面的所有对象做一次release操作会返回对象本身调用完autorelease方法后,对象的计数器不变autorelease的好处不用再关心对象释放的时间不用再关心什么时候调用releaseautorelease的使用注意占用内存较大的对象不要随便使用autorelease占用内存较小的对象使用autorelease,没有太大影响自动释放池在iOS程序运行过程中,会创建无数个池子。这些池子都是以栈结构存在(先进后出)当一个对象调用autorelease方法时,会将这个对象放到栈顶的释放池自动释放池的创建方式

iOS5.0前

NSAutoreleasePool*pool=[[NSAutoreleasePool

alloc]init];

[poolrelease];//[pooldrain];

iOS5.0开始@autoreleasepool{}在开发iOS程序时会自动创建autoreleasepoolautorelease的常见错误alloc之后调用了autorelease,又调用release。野指针错误。Person*p=[[[Person

alloc]init]autorelease];[prelease];连续调用多次autorelease,则在“自动释放池”销毁的时候对该对象做多次release。可能造成野指针错误。Person*p=[[[[Person

alloc]init]autorelease]autorelease];autorelease和release使用对比使用

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论