您的位置:首页 > 其它

内存管理

2015-07-27 22:12 309 查看
管理内存有三种方式

1:垃圾回收,java常见的管理内存的方法,系统来检测对象是否被回收使用,是否被释放.
2:MRC手动管理引入计数,iOS管理内存的方式,程序员通过手动的方式来管理对象是否被释放.
3:ARC自动管理引入计数,基于MRC,系统自动管理内存.
*以后我们还是先使用MRC,培养管理内存的习惯.


MRC手动管理规则

// 对象被创建出来之后他的引用计数retainCount就变成了1
Boy *boy = [[Boy alloc] init];
NSLog(@"%ld", boy.retainCount);


retain:对对象的引用计数+1

Boy *boy = [[Boy alloc] init];
[boy retain];
NSLog(@"%ld", boy.retainCount);


release:对对象的引用计数-1

Boy *boy = [[Boy alloc] init];
NSLog(@"%ld", boy.retainCount);
[boy retain];
NSLog(@"%ld", boy.retainCount);
[boy release];
NSLog(@"%ld", boy.retainCount);
// 当对象的引用对象计数1->0的时候,会自动调用dealloc,dealloc才是对应对象释放的方法
[boy release];
// 当对象调用release的时候, 它的引用计数是1,这个对象就不在对它的引用计数进行-1操作,而是直接调用dealloc方法,所以我们在访问对象的引用计数还是1
NSLog(@"%ld", boy.retainCount);
// 如果多次对对象进行释放,会造成过度释放,过度释放也是最常见的内存问题
[boy release];


NSString: 的对象在全局静态区,它的引用计数是-1, 代表了正整数的最大值,其他对象都在堆区

NSString *str = @"111";
NSLog(@"%ld", str.retainCount);
// 对于NSString, retain 和  release 没有用


自动释放池

// 只要对象用autoreleasepool 释放会把对象放入到系统的自动释放池中,等出了池子的范围,对象引用计数自动-1,这相当于java的垃圾回收,对象释放有系统来管理
// release 马上会把对象的引用计数-1,但是 autorelease 会延迟对对象的计数-1

Boy *boy = [[Boy alloc] init]; [boy retain]; NSLog(@"%ld", boy.retainCount);
@autoreleasepool {
[boy autorelease];
NSLog(@"%ld", boy.retainCount);
}
NSLog(@"%ld", boy.retainCount);


内存管理的原则: 加多少,对应减多少,加减做到平衡

对象的所有权: 拥有所有权的对象可以对他进行release

便利构造器在返回对象的时候会加上一个 autorelease ,所以用便利构造器创建对象不需要进行内存管理

NSArray *arr1 = [[NSArray alloc] initWithObjects:@"1", @"2", nil];
NSArray *arr2 = [NSArray arrayWithObjects:@"2", @"3", nil];
[arr1 release];
// arr2 便利构造器创建的对象,在main.m文件里不需要进行内存管理


id是泛型指针,可以用在任何方法中,但是instancetype代表实例类型,用在自定义初始化方法,便利构造器作为返回值类型使用,标识方法会返回一个对象回去



当对象放入到容器Array或字典中, 对象会被容器进行一次持有,就是retain一次,他的引用计数就会+1, 主要防止空指针的问题.

等对象从容器中移除掉之后,相应的会-1.

Boy *boy1 = [[Boy alloc] init];
[boy1 retain];
NSLog(@"%ld", boy1.retainCount);

NSMutableArray *arr = [NSMutableArray arrayWithObjects:boy1, nil];
NSLog(@"%ld", boy1.retainCount);

[arr removeObjectAtIndex:0];
NSLog(@"%ld", boy1.retainCount);


copy

// 系统的类要是实现copy拷贝的功能,必须先签订拷贝NSCopying的协议,然后实现对应的方法
// 不可变的数组方法字典可以通过mutableCopy转换成可变的数组字典
// mutableCopy出来的对象是可变的,Copy出来的对象是不可变的

NSArray *arr = @[@"1", @"2", @"3", @"4"];
NSMutableArray *arr1 = [NSMutableArray arrayWithArray:arr];
NSMutableArray *arr2 = [arr mutableCopy];
[arr2 addObject:@"5"];
NSLog(@"%@", arr2);

NSDictionary *dic = @{@"1" : @"2", @"3" : @"4"};
NSMutableDictionary *muDic = [dic mutableCopy];
NSLog(@"%@", muDic);
----------------------------------------------------------
// 如果自己的类想要实现copy的功能,就必须先签订NSCopying,然后实现对应的协议方法,initWithZone,之后就可以用copy的功能

Boy *boy = [Boy boyWithName:@"腾飞" hobby:@"吃"];
Boy *newBoy = [boy copy];
NSLog(@"%@", newBoy.name);

// boy.h文件

@interface Boy : NSObject<NSCopying>

@property(nonatomic, retain)NSString *name;
@property(nonatomic, copy)NSString *hobby;

-(instancetype)initWithName:(NSString *)name
hobby:(NSString *)hobby;

+(Boy *)boyWithName:(NSString *)name
hobby:(NSString *)hobby;

@end

// boy.m文件

-(instancetype)initWithName:(NSString *)name
hobby:(NSString *)hobby
{
self = [super init];
if (self) {
self.name = name;
self.hobby = hobby;
}
return self;
}

+(Boy *)boyWithName:(NSString *)name
hobby:(NSString *)hobby
{
Boy *boy = [[Boy alloc] initWithName:name hobby:hobby];
// 写便利构造器最后别忘了 autorelease
return [boy autorelease];
}

-(id)copyWithZone:(NSZone *)zone
{
Boy *b =[Boy allocWithZone:zone];

b.hobby = _hobby;
b.name = _name;
return b;
}


 属性的语义特性及使⽤用范围

//assign下的属性内部实现

//setter方法

@property(nonatomic,assign)NSString *name;

- (void)setName:(NSString *)name
_name = name;
}

//getter方法

- (NSString *)name{
return _name;
如果在 main.m中 按照下面方式去书写会出现问题

NSString *name = [[NSString alloc] initWithFormat:@”张三”];
Person *p = [[Person alloc]init];
[p setName:name];
[name release];
NSLog(@”%@”,[p name]); // 野指针异常
[p release];
----------------------------------------------------------
//retain下的属性内部实现

//setter方法
@property(nonatomic,retain)NSString *name;

- (void)setName:(NSString *)name
{
if(_name != name){
[_name release];
_name = [name retain];
}
}

//getter方法

- (NSString *)name
{
return [[_name retain]autorelease];
}

//main.m中

NSString *name = [[NSString alloc]
initWithFormat:@”张三”];
Person *p = [[Person alloc]init];
[p setName:name];
[name release];
NSLog(@”%@”,[p name]);
NSString *newName = [[NSString alloc]initWithFormat:@”李四”];
[p setName:newName];
[newName release];
NSLog(@”%@”,[p name]);
[p release];
----------------------------------------------------------
// copy下的属性内部实现

// setter方法

@property(nonatomic,copy)NSString *name;
- (void)setName:(NSString *)name
{
if(_name != name){
[_name release];
_name = [name copy];
}
}

// getter方法

- (NSString *)name{
return [[_name retain]autorelease];
}

// main.m中

NSString *name = [[NSString alloc]
initWithFormat:@”张三”];
Person *p = [[Person alloc]init];
[p setName:name];
[name release];
NSLog(@”%@”,[p name]);
NSString *newName = [[NSString alloc]initWithFormat:@”李四”];
[p setName:newName];
[newName release];
NSLog(@”%@”,[p name]);
[p release];


dealloc

dealloc是NSObject的⼀一个实例⽅方法,与alloc对应,⽤用于回收开辟的内 存空间

// Person.m中, 如何使⽤用dealloc

(void)dealloc
{

[_name release];//释放setter方法泄露的实例变量

[super dealloc];
}


构造器管理内存

-(id)initWithName:(NSString *)name age:(NSInteger)age
{
self = [super init];
if (self) {
self.name = name;
self.age = age;
// _age = age;
// 对象创建之后,里面的数组也会创建好,不用在外面创建, 避免因为忘了, 造成问题
self.arr = [NSMutableArray array];
}
return self;
}

+(Person *)personWithName:(NSString *)name age:(NSInteger)age
{
Person *per = [[Person alloc] initWithName:name age:age];
return [per autorelease];
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: