黑马程序员——OC基础---内存管理
来源:互联网 发布:sql server 2008r2 编辑:程序博客网 时间:2024/05/16 06:19
——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-
第一讲 内存管理的基本概念
为什么要内存管理?c语言中内存管理,函数在内存中堆区申请一些内存空间去(程序运行过程动态分配,链表的方式由程序员自己去管理)。
内存五大区域:1栈区 2堆区(程序运行) 3bss段 (没有初始化的全局变量和局部变量) 4数据区(已经初始化的) 5代码段。
移动设备的内存设备是极其有限的,必须考虑到内存的问题,如果一个app使用超过20M时候,会产生一个警告。
oc内存管理的范围
管理范围:管理任何继承NSObject的对象,对其他的基本数据类型无效。(因为基本数据类型数据占用的存储空间是固定的,一般存放在栈区)
对象类型是程序运行过程中的动态分配的,存储在堆区内存管理主要是对堆区中对象的内存管理。
第二讲 内存管理的原理和分类
内存不管理就会发生“内存泄漏”这里就会涉及到所有者,对象所有权的问题,任何对象都有可能一个或者多个所有者,只要一个对象拥有至少一个所有者,就会继续存在。
任何自己创建的对象都归自己所有,可以使用名称以“alloc”,“new”开头或者名称中包含“copy”的方法创建对象,可以使用retain来获取一个对象的所有权。或者使用“对象引用计数器”,每个oc对象都有自己的引用计数器,是一个整数表示对象被引用的次数。
第三讲 内存管理的原则
内存管理的原则:
1 只要还有人在使用这个对象,那么这个对象就不会被回收。
2 只要你想使用这个对象,那么就应该让这个对象的引用计数器+1
当你不想使用这个对象,应该让这引用计数器-1
注意事项:谁创建,谁release,如果你通过alloc,new.copy来创建一个对象,那么你就必须调用release或者autorelease方法
,不是你创建的就不用你负责。
第四讲 单个对象的内存管理
单个对象的野指针问题:
先看一个实例:
//用Person类实例化一个对象 Person *p = [Person new];//此时对象的所有者是自己 //证明该对象有一个所有者 NSInteger count = [p retainCount]; NSLog(@"count1 = %lu",count);[p eat]; //此时该对象的堆区内存空间已经释放,称为【僵尸对象】 [p release]; //验证当对象在堆区的空间已经释放了,那么还能在使用p么? //这种情况默认不会报错,如果要检测,需要开启僵尸对象检测 [p eat];//野指针访问
为了避免使用僵尸对象的方法就是对象释放完以后,给对象赋值为nil(对象空值)。
单个对象内存泄漏问题:
1 创建完成,使用之后,没有release
2 没有遵守内存管理的原则
3 不当的使用nil
4 在方法中对传入的对象进行了retain
第五讲 多个对象的内存管理
一句话代码引发的bug:
Person *p=[Person new];Car *car=[Car new];[p setCar:car];[p driver];[car release];[p driver];[p release];
p对象在没有销毁之前,可以任意多次调用自己的对象方法,但是此时会报错(注意僵尸对象检测)
第六讲 set方法内存管理
在OC中,每一个对象都有一个引用计数,来判断有多少个单位正在使用该对象,当引用计数为0时,说明没有单位再使用这片空间了,就会调用该对象的dealloc方法,将其抹掉,有的时候会出现这样一种情况,一个对象是另一个对象的属性(一般是用SET方法设置),这时我们便有必要理顺他们在内存之中的关系了。比如说一个Human类,一个Hands类,Hands对象又是Human对象的一个变量,注意,这个时候会出现一个问题:如果Human对象被释放的话,连带着Hands对象也会被释放,而如果在main中之后我们还需要使用Hands对象的话,我们就不得不再new一个,但很多人注意不到这点,总是不知道问题出现在哪里。为了解决这个问题,我们需要在Human类对象引用Hands类对象时,手动增加Hands类对象的一个引用计数
#import "Human.h" @implementation Human -(void)setHand:(Hands *)newHand { [newHand retain]; hand=newHand; } @end
但是这时又会出现一个问题,Hands可以有多个对象,比如leftHand,rightHand,如果我先以leftHand为参数,这样leftHand会在内存中有两个引用,一个main生成的,一个Human类对象生成的,如果我再次调用setHand方法,这次以rightHand方法为参数,同样rightHand有两个引用计数,一个main生成的,一个Human类对象生成的。这时问题就出现了,leftHand在内存中是占有空间的,它在main方法中的计数会被释放,但在Human类对象中永远都释放不了了,因为Human类对象释放的话只会释放rightHand的引用计数了。这样被遗忘的leftHand会一直在那个内存的角落里默默流泪。于是有的同学便会说,那先把leftHand释放了啊,于是就有了下面这样的代码:
#import "Human.h" @implementation Human -(void)setHand:(Hands *)newHand { [hand release]; [newHand retain]; hand=newHand; } @end
第七讲 @property参数的介绍
首先,我们看atomic 与nonatomic的区别与用法,讲之前,我们先看下面这段代码:
@property(nonatomic, retain) UITextField *userName; @property(nonatomic, retain,readwrite) UITextField *userName; @property(atomic, retain) UITextField *userName; @property(retain) UITextField *userName; @property(atomic,assign) int i; @property(atomic) int i; @property int i;
上面的代码atomic是默认,assign是默认,readwrite是默认。
但是,如果你写上@property(nontomic)NSString *name;那么将会报一个警告。因为是非gc的对象,所以默认的assign修饰符是不行的。那么什么时候用assign、什么时候用retain和copy呢?推荐做法是NSString用copy,delegate用assign(且一定要用assign,不要问为什么,只管去用就是了,以后你会明白的),
非objc数据类型,比如int,float等基本数据类型用assign(默认就是assign),而其它objc类型,比如NSArray,NSDate用retain。
在继续之前,我还想补充几个问题,就是如果我们自己定义某些变量的setter方法,但是想让编译器为我们生成getter 方法,这样子可以吗?答案是当然可以。如果你自己在.m文件里面实现了setter/getter方法的话,那么编译器就不会为你再生成相应的 getter/setter了。请看下面代码:
//代码一:@interface BaseClass : NSObject{@public NSString *_name;}@property(nonatomic,copy,readonly) NSString *name; //这里使用的是readonly,所以会声明geter方法-(void) setName:(NSString*)newName;//代码二:@interface BaseClass : NSObject{@public NSString *_name;}@property(nonatomic,copy,readonly) NSString *name; //这里虽然声明了readonly,但是不会生成getter方法,因为你下面自己定义了getter方法。-(NSString*) name; //getter方法是不是只能是name呢?不一定,你打开Foundation.framework,找到UIView.h,看看里面的property就明白了)-(void) setName:(NSString*)newName;//代码三:@interface BaseClass : NSObject{@public NSString *_name;}@property(nonatomic,copy,readwrite) NSString *name; //这里编译器会我们生成了getter和setter//代码四:@interface BaseClass : NSObject{@public NSString *_name;}@property(nonatomic,copy) NSString *name; //因为readwrite是默认行为,所以同代码三复制代码 上面四段代码是等价的,接下来,请看下面四段代码: 复制代码//代码一:@synthesize name = _name; //这句话,编译器发现你没有定义任何getter和setter,所以会同时会你生成getter和setter//代码二:@synthesize name = _name; //因为你定义了name,也就是getter方法,所以编译器只会为你生成setter方法,也就是setName方法。-(NSString*) name{ NSLog(@"name"); return _name;}//代码三:@synthesize name = _name; //这里因为你定义了setter方法,所以编译器只会为你生成getter方法-(void) setName:(NSString *)name{ NSLog(@"setName"); if (_name != name) { [_name release]; _name = [name copy]; }}//代码四:@synthesize name = _name; //这里你自己定义了getter和setter,这句话没用了,你可以注释掉。-(NSString*) name{ NSLog(@"name"); return _name;}-(void) setName:(NSString *)name{ NSLog(@"setName"); if (_name != name) { [_name release]; _name = [name copy]; }}
上面这四段代码也是等价的。看到这里,大家对Property的作用相信会有更加进一步的理解了吧。但是,你必须小心,你如 果使用了Property,而且你自己又重写了setter/getter的话,你需要清楚的明白,你究竟干了些什么事。别写出下面的代码,虽然是合法 的,但是会误导别人。
- 黑马程序员——OC基础——内存管理
- 黑马程序员——OC基础—内存管理
- 黑马程序员——OC基础03—内存管理
- 黑马程序员——OC基础---内存管理
- 黑马程序员——OC语言基础篇---内存管理
- 黑马程序员—OC语言基础—内存管理
- 黑马程序员——IOS基础(OC内存管理)
- 黑马程序员—IOS基础之OC—内存管理
- 黑马程序员——OC基础---手动内存管理
- 黑马程序员——OC基础---内存管理
- 黑马程序员——OC---内存管理
- 黑马程序员——OC内存管理
- 黑马程序员——OC内存管理
- 黑马程序员——【OC】内存管理
- 黑马程序员——OC内存管理
- 黑马程序员——OC内存管理
- 黑马程序员——OC内存管理
- 黑马程序员——OC内存管理
- 迷之好奇
- CSS样式表中的z-index总结
- 面向对象(代码块、继承)
- 小鑫爱数学
- 51单片机驱动HC-SR04超声波测距模块(LED1602显示结果)
- 黑马程序员——OC基础---内存管理
- 面向对象(多态、抽象类、接口)
- 图的基本存储的基本方式一
- html 属性大全
- 一维数组、二维数组
- android .9.png ”点九” 图片制作方法
- 图的基本存储的基本方式二
- 2015年大二上-数据结构-串(3)- 顺序串算法
- 图的基本存储的基本方式三