[学习笔记—Objective-C]《Objective-C-基础教程 第2版》第九章 内存管理

内存管理:

  • 确保在需要的时候分配内存,在程序运行结束时释放占用的内存
  • 如果只分配内存而不释放内存,则会发生内存泄漏(leak memory),程序的内存占用量不断增加,最终会被耗尽并导致程序崩溃。
  • 不要使用任何刚释放的内存,否则可能误用陈旧的数据,如果内存已经加载了其他数据,将会破坏这些新数据。

9.1 对象生命周期

对象的生命周期:

  1. 诞生:通过alloc或new方法实现
  2. 生存:接受消息并执行操作
  3. 交友:通过复合以及向方法传递函数
  4. 死去:被释放掉

9.11 引用计数

关于引用计数的操作:

  • 增加对象的保留计数器的值:发送retain 。方法:-(id) retain //返回值为id类型
[[Car retain] setTire: tire atIndex:2];//car对象保留计数器的值+1并执行setTire的操作
  • 减少对象的保留计数器的值:发送release。方法:(oneway void)release;
  • 获得保留计数器当前的值:retainCount。方法:-(NSUInteger) retainCount;//格式化方法:%ld
  • 对象的保留计数器归0时,系统会自动向对象发送dealloc消息。
  • 可以在自己的对象中重写dealloc方法,这样可以释放掉已经分配的全部相关资源,不能直接调用dealloc方法。

9.12 对象所有权

  • 某个实体拥有一个对象时,该实体就要负责将其拥有的对象进行清理
    • 如果一个对象内有指向其他对象的实例变量,则称该对象拥有这些对象
    • 如果一个函数创建了一个对象,则称该函数拥有这个对象
main(){
Car *car = [Car new];
Engine *engine = [Engine new];//engine拥有engine对象

[car setEngine: engine];//car拥有engine对象
}

注意:main()和Car类都拥有engine对象,如何释放?

  • 让Car类在setEngie方法中保留engine对象,main()负责释放engine对象,Car类完成任务时再释放engine对象

9.13 访问方法中的保留和释放

-(void)setEngine: (Engine *)newEngine
{
    [newEngine retain];    //先保留新的对象
    [engine release];      //释放旧的对象
    engine = newEngine;

9.14 自动释放

-(NSString *) description
{
    NSString *description = [[NSString alloc] initWithFormat:@"I am %d years old", 4];
    return (destription);
}

main{
    NSString *desc = [someObject description];
    NSLog(@"@",desc);
    [desc release];
}

注意:在description方法中创建的字符串对象如何释放?

9.15 所有对象放入池中

-(id)autorelease;//返回接受这条消息的对象
  • 当给一个对象发送autorelease消息时,是将对象添加到了自动释放池中,当自动释放池被销毁时,会像该池中的所有对象发送release消息。
-(NSString *) description
{
    NSString *description = [[NSString alloc] initWithFormat:@"I am %d years old", 4];
    return ([destription autorelease]);//对象暂时放入池中,等调用NSLog代码结束后,自动释放池会被自动销毁
}

main(){
    NSLog(@"@",[someObject description]);
}

9.16 自动释放池销毁时间 略

9.17 自动释放池的工作流程


int main ()
{
    NSAutoreleasePool *pool;
    pool = [[NSAutoreleasePool alloc] init];

    RetainTracker *tracker;
    tracker = [RetainTracker new]; // count: 1

    [tracker retain]; // count: 2
    [tracker autorelease]; // count: still 2,自动释放池有一个引用指向了该对象,当自动释放池被销毁时,将给tracker对象发送一条release消息。保留计数器的值仍然大于0,仍处于活动状态。

    [tracker release]; // count: 1

    NSLog (@"releasing pool");
    [pool release]; //dealloc方法调用

    return (0);
}

9.2 Cocoa的内存管理规则

  • 使用new,alloc,或copy方法创建对象时,该对象的保留计数器为1。
  • 如果通过其他对象获得一个对象时,假设该对象的保留计数器值为1,而且一景被设置为自动释放,那么不需要执行任何操作确保该对象得到清理。
  • 如果打算一段时间拥有对象,则需要保留它并确保在操作完成时释放它。
  • 如果保留了某个对象,就需要最终释放或自动释放该对象。必须保持retain方法和release方法的使用次数相等。

注意:当拥有一个对象的时候,需要弄清楚:怎样获得对象的?打算拥有多长时间?

9.21 临时对象

并未打算长期拥有对象的情况下:临时对象

  • 如果是用new,alloc,copy方法获得的这个对象,就需要安排好该对象的内存释放
  • new,alloc,copy以外的方法获得对象,则可以假设该对象被返回时保留计数器的值是1而且被设置为自动释放。

9.22 拥有对象

在多段代码中一直拥有某个对象,将她们加入到诸如NSArray或NSDictionary集合中

  • 如果使用了new,alloc,copy方法获得了一个对象,只需要在拥有该对象的dealloc方法中释放它即可。
-(void)dostuff
{
    flonkArray = [NSMutableArray new]; //count:1
}
-(void) dealloc
{
    [flonkArray release]; //count:0
    [super dealloc];
}
  • 如果使用new,alloc,copy以外的方法获得了一个对象,需要保留该对象,因为在事件循环结束后或自动释放池被销毁时,该对象会收到一条release消息。
-(void)dostuff
{
    flonkArray = [NSMutableArray arrayWithCapacity:17]; //count:1,autoreleased

}
-(void) dealloc
{
    [flonkArray release]; //count:0 
    [super dealloc];
}

注意:自动释放池被清理的时间是完全确定的:在代码中你自己手动销毁;使用AppKit时在事件循环结束时结束。

9.23 垃圾回收:自动内存管理机制

垃圾回收器定期检查变量和对象并且跟踪它们的指针,发现没有任何变量指向某个对象时,就将该对象视为应该丢弃的垃圾。

如果实例变量指向某个对象,一定要将该实例赋值为nil,取消对该对象的引用并告知垃圾回收器该对象可以清理了。

注意:

  • 垃圾回收只支持OSX开发,无法用在ios应用程序上。苹果公司不建议在自己的代码中使用autorelease方法,也不要使用会返回自动释放对象的一些便利的方法:stringWith:
  • 垃圾回收器在运行时工作,通过返回的代码定期检查对象

9.24 自动引用计数

  • 自动引用计数(automatic refrence counting,ARC):系统追踪对象并决定哪一个仍会使用,哪一个不会再用到。

  • ARC在编译时进行工作的,在代码中插入了retain和release语句。

  • 有效范围:可保留的对象指针

    • 代码块指针
    • Objective-C指针
    • 通过attribute((NSObject))类型定义的指针
  • 使用ARC满足的条件:

    • 能够确定哪些对象需要内存管理
    • 能够表面如何管理对象
    • 有可行的办法传递对象的所有权
  • A引用了B,B的引用计数器+1,强指针;被引用的+1

  • A释放了B,B的引用计数器-1;被释放的-1

  • 归零弱引用:zeroing weak reference 若引用的对象被释放的情况下,若引用会被设置为0

声明归零弱引用:

  • _weak NSString *mystring
  • @property (weak) NSString *myString

注意:内存管理的关键字和特性是不能一起用的

垃圾回收机制禁用的前提下才能使用ARC
转换之前确保代码符合ARC的需求
一旦转换成ARC版本,就不可以再恢复了

  • 拥有者权限:为了让ARC便于工作,需要告诉编译器哪个对象时指针的拥有者。

    • (_bridge)传递指针但不会传递它的所有权
    cfstring = (_bridge CFStringRef)theString;
    //指针的所有权仍然由theString保留
    
    • (_bridge_retain):所有权转移到non-ROP上

      cfstring = (_bridge_retain CFStringRef)theString; 
      //cfstring拥有指针并且保留计数器+1
    • (_bridge_transfer):所有权交给ROP

      ARC拥有对象并能确保它会像其他ARC对象一样得到释放

9.3 异常

NSException类来表示异常

  • 抛出异常(提出异常):处理异常的行为,通知异常的行为
  • 捕捉异常:处理被抛出的异常的行为

如果一个异常被抛出但是没有被捕捉到,程序会在异常断点处停止运动并通知有这个异常。

9.31 与异常有关的关键字

  • @try:定义用来测试的代码块决定是否抛出异常
  • @catch:定义用来处理已抛出异常的代码块
  • @finally:无论是否有抛出异常都会执行代码块
  • @throw:抛出异常

9.32 捕捉不同类型的异常

  • 多个@catch代码块,处理代码应该按照从具体到抽象的顺序排序

9.33 抛出异常

  • 当程序检测到了异常,就必须向处理它的代码块报告这个异常
    • 使用@“throw异常名”
    • 向某个NSException对象发送raise消息
NSException *theException = [NSException exceptionWithName: ];
@throw theException; //抛出异常,可以用在其他对象上
[theException rasie];//抛出异常,raise只对NSException对象有效
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值