2013-07-08 OC内存管理
来源:互联网 发布:简单的化工制图软件 编辑:程序博客网 时间:2024/06/06 13:03
内存管理的必要性
内存空间的有限性,手持移动设备的易发热性
所有权机制
1)只有当你对一个对象做了alloc,copy或retain等操作后,你才拥有它的所有权;
2)当你不在需要使用这个对象是,应该释放你对它的所有权;
3)你不能对你没有所有权的对象执行释放操作;
获得所有权的方法
1)alloc:为一个新对象分配内存,并将应用计数置1;
2)retain:对象的应用计数+1;
3)copy:制造元对象的副本,该副本的引用计数为1,调用拥有该副本的所有权,并在赋值前释放原油对象,然后在进行赋值;
释放所有权
1)release:
2)autorelease:
dealloc方法
1)dealloc方法会在对象引用计数为0时被系统调用;
2)dealloc不需要手动调用,二十让系统自动调用;
3)对象师傅的时候需要把自己所包含的对象变量一并释放掉;
-(void)dealloc
{
[_name release];//因为name的属性声明是retain,所以在dealloc方法中要释放这个属性
[super dealloc];//最后释放本类对象
}
内存管理
示例一
使用alloc创建对象,则需要在使用完后进行释放
Person *person1 = [[Person alloc]initWithName:@”张三”];
NSLog(@”name is %@”,person1.name);//假设从这往后,我们一直都不使用person1了,应该把对象给释放了。
[person1 release];
示例二
Person *person2 = [Person alloc]initWithName:@”李四”];
NSString *name = person2.name;NSLog(@”%@”,name);//假设从这以后,我们也不使用person2了。[person2 release];
我们不应该释放name,因为name是我们间接获得的,所以没有它的所有权,也不应该对它进行释放。
自动释放池
autorelease pool 在新建一个项目的时候,Xcode会自动帮我们生成。
便利构造器的管理
错误示例一
+(id) personWithName:(NSString *)aName
{
Person *person = [[Person alloc];
initWithName:aName];
return person;
}
它是错误的,因为它返回了新创建的对象以后,类就失去了释放这个对象的机会。错误示例二
+(id) personWithName:(NSString *)aName
{
Person *person = [[Person alloc];
initWithName:aName];
[person release];
return person;
}
它也是错误的,因为在返回对象的时候,对象 已经被销毁,从而不能使用了。
正确示例
+(id)personWithName:(NSString *)aName
{
Person *person = [[Person alloc]init];
[person autorelease];
return person;
}
它把对象的销毁延迟进行,从而使用者有时间去使用它,而又不必对对象的释放负责。
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[])
{NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
NSString *string = [[NSString stringWithFormat:@"hello word!"]init];
NSLog(@"%@",string);
[pool release];
return 0;
}
用便利构造器创建一个字符串对象string,则在使用完毕后不用去释放string。除了自动释放池后,string被自动自动销毁。
接口文件 (.h)
@interface MyClass : NSObject
{
NSString *_name;
}
@property(nonatomic,retain)NSString *name;
@end
设置器的实现
在设置器中,保持对新传入对象的所有权,同时放弃旧对象的所有权
-(void)setName:(NSString *)aname
{
if (_name != aname)
{
[_name release];
_name = [aname retain];//或者copy _name = [aname copy]
}
}
-(NSString *)name
{
return _name;
}
代码案例
声明文件中(.h)
//
// Person.h
// 内存管理
//
// Created by 0101 on 13-7-9.
// Copyright (c) 2013年 PH. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface Person : NSObject
{
NSString *_name;
}
-(void)setName:(NSString *)newName;
-(id)name;
@end
实现文件中(.m)
//
// Person.m
// 内存管理
//
// Created by 0101 on 13-7-9.
// Copyright (c) 2013年 PH. All rights reserved.
//
#import "Person.h"
@implementation Person
-(void)setName:(NSString *)newName
{
if(_name != newName)//如果当前传入的对象不是新的对象
{
[_name release];//那么就将放弃旧对象
_name = [newName retain];//保持对新对象的所有权
}
}
-(id)name
{
return _name;
}
@end
//
// main.m
// 内存管理
//
// Created by 0101 on 13-7-9.
// Copyright (c) 2013年 PH. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[])
{
/*
Person *person1 = [[Person alloc]init];
NSLog(@"retainCount=%ld",[person1 retainCount]);//创建一个新的对象person1,并且alloc 引用计数retainCount=1,获得所有权
NSString *newName1 = [[NSString alloc]initWithFormat:@"名字1"];
NSLog(@"retainCount=%ld",[newName1 retainCount]);//创建一个新的对象newName,此时他还没有指向person1,因此retainCount还是等1
[person1 setName:newName1];//把newName初始化的“名字1”传给了setName中的参数name,相当于retain了一次,此时retainCount=2
NSLog(@"retainCount=%ld",[newName1 retainCount]);
[newName1 release];
NSLog(@"retainCount=%ld",[newName1 retainCount]);//newName1 release了一次,retainCount=1
NSLog(@"*******************************");
NSString *newName2 = [[NSString alloc]initWithFormat:@"名字2"];//又创建了一个新对象newName2并且alloc
NSLog(@"retainCount=%ld",[newName2 retainCount]);
[person1 setName:newName2];
NSLog(@"retainCount=%ld",[newName2 retainCount]);
[newName2 release];
NSLog(@"retainCount=%ld",[newName2 retainCount]);
NSLog(@"person`s name = %@",[person1 name]);
[person1 release];//同时系统调用dealloc方法将@“名字2”也释放了,@“名字2”的引用计数为0
NSLog(@"*******************************");
NSLog(@"retainCount=%ld",[newName2 retainCount]);
// NSLog(@"retainCount=%ld",[newName1 retainCount]);
*/
Person *person1 = [[Person alloc]init];//person1 retainCount = 1
NSString *newName1 = [[NSString alloc]initWithFormat:@"名字1"];//newName1 retainCount = 1
[person1 setName:newName1];//newName retainCount = 2
[newName1 release];//newName1 retainCount = 1
[person1 setName:[person1 name]];//在Person.m的设置器中[_name release] name已经被释放掉了,_name = [newName retain];,newName指向了一块释放掉的内存,导致程序崩溃
NSLog(@"person name = %@",[person1 name]);
return 0;
}
在访问器中不需要retain或release
示例
用访问器获得的对象,使用完毕后不需要释放。
-(NSString *)name
{
return name;
}
-(void) printName
{
NSString *name = person.name;
NSLog(@”%@”,name);
}
1)使用alloc为对象分配内存,使用-dealloc释放对象所占用的内存,dealloc是个方法
2)使用alloc,new,或者copy构造对象时,对象的retainCount为1;
3)调用对象的retain方法可以增加1 retainCount;
4)调用对象的release可以减少1 retianCount;
5)只有 retain count等于0,系统才会调用dealloc真正销毁这个对象。当对象的retianCount为0时,dealloc会自动调用,释放对象内存(也就是说只有retainCount等于0,系统才会);否则分配给对象的内存将一直占用
6)所有对象可以使用热天C偶耐他属性查看当前的计数值;
引用计数是针对内存的
会影响计数器的操作:
1)alloc创建一个对象,并将其引用计数设为1,并拥有对象所有权
2)copy制造一个副本,并将副本的引用计数设为1,并拥有副本所有权
3)retain时对象引用技术加1,并拥有对象所有权
4)release使对象引用技术减1,并放弃对象所有权
5)autorelease向autoreleasepool注册
栈区是不需要进行所谓的内存释放的 实例变量是存放在堆栈中的
属性内存管理
如果属性是对象类型,关键字用retain
声明成retain属性默认实现方式
-(void)setName:(NSString *)name
{
if (_name != name)
{
[_name release];
_name = [name retain];
}
}
-(NSString *)name
{
return _name;
}例如:
//在MyClass.h中声明了两个属性
#import <Foundation/Foundation.h>
#import "Student.h"
/*
班级实体类
*/
@interface MyClass : NSObject
{
NSString *_name;
Student *_stu1;//Student类型的学生类
}
@property(nonatomic,retain)NSString *name;
@property(nonatomic,retain)Student *stu1;//因为*stu1属性是对象类型的,所以修饰符用retain
@end
//MyClass.m
#import "MyClass.h"
@implementation MyClass
@synthesize name=_name,stu1=_stu1;
-(void)dealloc
{
[_stu1 release];
[_name release];
[super release];
}
@end
//AppDelegate.m
Student *s = [[Student alloc]init]; //alloc一次s的retainCount=1,并获得控制权限
//属性的内存管理
MyClass *cls = [[MyClass alloc]init];
cls.stu1 = s;//将对象s赋给*cls的属性stu1,此时stu1的retainCount=2,并获得控制权限
[s release]; //释放对象s,此时s的retainCount=1;内存释放原则一:
1)对象分配内存,并应在使用后,调用release释放内存;
2)凡是出现retain,copy,alloc的地方,都应出现release与之匹配;
3)如果声明属性是对象类型(var),属性关键字用retain,且在此类delloc方法中把_var实例变量release一次;
autorelease的使用之处
1)在便利构造器中使用,也就是使用便利构造器获得对象,都(应)是autorelease的
2)内存无法确定释放时间时,可以使用autorelease相最近的池注册
3)有池决定释放所有权时间
原则
1.黄金法则:当有权利使用alloc copy retain,new,就有义务release
自动释放池
当创建的对象未来某个时候销毁时,可以使用对象的autorelease
内存检测的两个方法
1)选中文件-->Build Setting-->All-->输入static-->选择Run static Analyzer-->选中YES
2)product-->profile-->Leaks-->
小结
初始化方法写完后,立马写dealloc方法
- 2013-07-08 OC内存管理
- OC内存管理-OC笔记
- OC内存管理
- Oc-内存管理
- OC内存管理
- OC 内存管理
- oc 内存管理
- OC内存管理
- oc -内存管理 笔记
- OC之【内存管理】
- OC内存管理小记
- OC内存管理(转载)
- OC-内存管理
- 2、OC内存管理
- Oc内存管理
- OC高级内存管理
- OC-内存管理
- OC的内存管理
- 2013-07-02 实例变量 、 属性 、便利构造器、设置器、 访问器、实例方法("-") 、类方法("+"静态方法)、单例
- JS获取textarea的光标位置并插入内容
- C++11: Standards, Compilers and IDEs
- 2013-07-08 C_Language
- 关于懒加载的错误
- 2013-07-08 OC内存管理
- c语言编程规范
- 数据工程师必掌握的算法:蓄水池算法发布时间
- 动态调整UITableViewCell高度的实现方法
- 2013-07-07 C_Language
- win7系统下远程桌面控制Redhat服务器
- PHP上传文件
- c 和 c++ 中的 函数void形参和空形参的区别
- UVA 820 Internet Bandwidth 最大流入门