黑马程序猿_OC之内存管理

看完了OC视频里面的内存管理,之前对于内存管理很陌生,可以说几乎没有接触过,才知道写代码内存管理的重要性,下面简单总结一下学习笔记

1.retain跟release的基本概念

像一般的数据类型int、double、char,这种类型的数据是系统自动回收内存空间的,但是OC对象是需要手动回收的(不用ARC机制),怎么回收呢?

内存管理的原理:每个OC对象都有自己的引用计数器,是一个整数,表示“对象被引用的次数”,在对象内部有4个字节的存储空间存储引用计数器,当使用alloc、new或者copy创建一个新对象时,新对象的引用计数器默认为1,当一个对象的引用计数器值为0时,对象占用的内存就会被系统回收,否则一直不会回收,直到程序退出。

那计数器怎么加1,怎么减1呢?

给对象发送一条 retain消息,可以使引用计数器值+1;给对象发送一条 release消息,可以使引用计数器值-1;而给对象发送一条 retainCount消息,获取当前引用计数器的值

那retain、release使用规则是什么呢?

使用retain 加1,release减1是有规则的,不能随便乱加乱减的:使用某一个对象,就让对象的计数器+1,让对象做一次retain操作,不再使用对象,就让对象的计数器-1,让对象做一次release;并且谁retain  谁release;谁alloc 谁release

当一个对象被销毁时,系统会自动向对象发送一条dealloc消息。可以重写dealloc方法,但是不能直接调用dealloc方法。

#import<Foundation/Foundation.h>

@interface Person:NSObject
@end

@implementation Person
- (void) dealloc
{
NSLog(@"对象被回收");
[super dealloc];    // 一定要调用父类的dealloc,并且放在重写dealloc代码的最后
}
@end

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

 [p retain];  // 返回对象本身p,计数器+1

 [p release]; // 没有返回值,计数器-1
 [p release]; // alloc对应的release
// 释放完了对象,不能在一直释放了,会报野指针的错误
  return 0;
}
上面这段代码是简单的alloc、retain、release的应用示例,所谓的野指针错误是指:指向了僵尸对象(不可用内存)的指针,僵尸对象是指所占用内存已经被回收的对象,不可用的对象。为了防止指针变成野指针,在没有ARC机制的情况下,一般是对象回收后,加 p = nil; 将指针清空,变成空指针。OC中给空指针发送消息不会报错,不存在空指针错误。

2.多对象内存管理

多对象内存管理是在一个对象拥有另外一个对象的情况下对内存的管理

#import <Foundation/Foundation.h>

@interface Book:NSObject
{
  int _price;
}
@end

@implementation Book

- (void)dealloc
{
  NSLog(@"书被回收了");
  [super dealloc];
}
@end

@interface Person:NSObject
{
   Book *_book;
}
- (void)setBook:(Book *)book;
- (Book *)book;
@end

@implementation Person
- (void)setBook:(Book *)book
{
  _book = [book retain];  // 当把一个对象赋值给_book时,说明_book使用这个对象,那此对象的计数器就要加1
}
- (Book *)book
{
 return _book;
}

- (void)dealloc
{
  [_book release];     // 当人这个对象被回收了,他拥有的书的资源也要释放了,所以让书对象的计数器减1
  NSLog(@"人被回收了");
  [super dealloc];
}
@end

int main()
{
 Book *b = [[Book alloc] init];
 Person *p = [[Person alloc] init];

 [p setBook:b];
 
 [b release];  // 书对象的计数器减1,b不再指向书对象
 b = nil;  // 清空指针

 [p release];  // 人对象的计数器减1,为0,内存回收,回收前执行dealloc,将书对象的计数器也减1,书对象也回收
  p = nil; 

  return 0;
}

3.property的内存管理

我们前面已经讲过,setter跟getter都是通过property来自动生成的,那再property里面怎么来时候内存管理呢?前面那个例子我们假设人要换一本书了,是不会对原来的书做一次release的,因为人没有销毁,所以set方法还需要完善

-  (void)setBook:(Book *)book
{
 if (_book != book)
{
  _book release;
  _book = [book ratain];
 }
}

而property的@property(retain)Book *book;这一句相当于前面一段set方法,因此又可以利用property来自动生成setter跟getter,还可以做好内存管理。但是dealloc还是要写的

- (void)dealloc
{
 [_book release];
 [super dealloc];
}

property的四大类参数


1.set方法内存管理相关的参数
retain:release旧值,retain新值(适用于OC对象类型)
assign:直接赋值(默认,适用于非OC对象类型)
copy:release旧值,copy新值

2.是否要生成set方法
readonly: 只生成getter的声明、实现
readwrite:同时生成getter和setter的声明、实现(默认)

3.多线程管理
nonatomic:性能高(一般要加上的)
atomic:性能低(默认)

4.setter和getter方法的名称,设置方法名称
@property(getter = abc,setter = setAbc:) int weight

4.autorelease

autorelease是对象方法,返回对象本身,可以取代release,调用autorelease方法,会将对象放到一个自动释放池中,当自动释放池被销毁时,会对池子里面的所有对象做一次release;调用autorelease方法后,对象的计数器不变,等释放池销毁才会release一次。可以创建很多个释放池,并且释放池可以嵌套,释放池在内存中以栈结构存放。

int main()
{
@autoreleasepool{  // 创建了释放池
Person *p = [[[Person alloc]  init ] autorelease];
p.age = 10;
}  // 代表销毁释放池

autorelease的错误写法:

1.alloc之后调用了autorelease,又调用了release
@autoreleasepool
{
 Person *p = [[[Person alloc] init]  autorelease];
 [p release];
}
2.连续调用多次autorelease
@autoreleasepool
{
 Person *p = [[[[Person alloc] init] autorelease] autorelease];
}
}

5.ARC

利用arc内存管理机制,很大程度上取代了人为内存管理。ARC判断准则:只要没有强指针指向对象,就会释放对象。默认情况下所有的指针都是强指针, 弱指针_weak 。

ARC特性:
1.不允许调用release、retain、retainCount
2.允许重写dealloc,但是不允许调用[super dealloc]
3.strong weak 都只适用于OC对象类型,在OC对象类型里,weak相当于assign的作用

-weak Person *p = [[Person alloc] init]; 没有意义的写法,对象一创建就被释放了,弱指针也清空了,p里面是null。

在arc机制中,以@property(nonatomic,strong) Dog *dog; 替代 @property(nonatomic,retain) Dog *dog;

#import <Foundation/Foundation.h>

@interface Person:NSObject
@property(nonatomic,weak) Dog *dog;
@end  

@implementation Person
@end

int main()
{
Dog *d = [[Dog alloc] init]; 
Person *p = [[Person alloc] init];
p.dog = d ;  // p对象里面的_dog成员变量也指向d对象,但是是弱指针
d = nil;    // d指针一清空,没有强指针指向狗对象,狗对象释放内存
NSLog(@"%@",p.dog);
return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值