OC内存管理三

一、 循环retain的场景
• 比如A对象retain了B对象,B对象retain了A对象
• 循环retain的弊端
• 这样会导致A对象和B对象永远无法释放
• 循环retain的解决方案
当两端互相引用时,应该一端用retain、一端用assign(weak)

二、@class
1、@class的使用

在.h文件中使用@class引用一个类

在.m文件中使用#import包含这个类的.h文件

@class 和 #import 的区别

这两种的方式的区别在于:

1)#import方式会包含被引用类的所有信息,包括被引用类的变量和方法;@class方式只是告诉 编译器在A.h文件中 B *b 只是类的声明,具体这个类里有什么信息,这里不需要知道,等实现文 件中真正要用到时,才会真正去查看B类中信息;

2)使用@class方式由于只需要只要被引用类(B类)的名称就可以了,而在实现类由于要用到被 引用类中的实体变量和方法,所以需要使用#import来包含被引用类的头文件;

3)通过上面2点也很容易知道在编译效率上,如果有上百个头文件都#import了同一 个文件,或 者这些文件依次被#improt(A->B, B->C,C->D…),一旦最开始的头文件稍有改动,后面引用到这 个文件的所有类都需要重新编译一遍,这样的效率也是可想而知的,而相对来 讲,使用@class方 式就不会出现这种问题了;
所以:我们实际开发中尽量在.h头文件中使用@class

4)对于循环依赖关系来说,比方A类引用B类,同时B类也引用A类,B类的代码:
当程序运行时,#import编译会报错,

三、NSString的内存管理问题

1—> NSString *str = [[NSString alloc] initWithString:@”ABC”];
2—> str = @”123”;
3—> [str release];
4—> NSLog(@”%@”,str);
首先,咱们先对这段代码进行分析。
第一句 声明了一个NSString类型的实例 str, 并将其初始化init后赋值为@”ABC” 第二行,将str的指针指向了一个常量@”123”。 理论上讲在第一行初始化的@”ABC”没有任何任何 指针指向了。 所以造成了内存泄露
然后第三行, 将str的引用计数-1
第四行输出str的值 为123.
首先回答为什么不会崩溃, 因为第三行的release 实际上是release了一个常量@”123” 而作为 常量,其默认的引用计数值是很大的(100k+)
NSLog(@”retainCount = %tu”,[@”123” retainCount]); 最终的输出值会是一个很大很大的数。 所以单单一个release是不会将其释放掉的。
然后再回答这样会不会造成内存泄露。
其实…………理论上讲 会! 但是实际上,Objective-C对NSString类型有特殊照顾。所有的NSString的引用计数器默认初始值 都会非常非常大。

三、autorelease自动释放池基本使用

• autorelease方法的基本作用
• 1、给对象发送一条autorelease消息, 会将对象放到一个自动释放池中
• 2、当自动释放池被销毁时,会对池子里面的所有对象做一次release操作
• 3、会返回对象本身
• 4、调用完autorelease方法后,对象的计数器不变

• autorelease的好处
• 不用再关心对象释放的时间
• 不用再关心什么时候调用release

• autorelease的使用注意

• 占用内存较大的对象不要随便使用autorelease
• 占用内存较小的对象使用autorelease,没有太大影响

• 自动释放池:
• 在iOS程序运行过程中,会创建无数个池子。这些池子都是以栈结构存在(先进后出)
• 当一个对象调用autorelease方法时,会将这个对象放到栈顶的释放池
• 自动释放池的创建方式】

• iOS 5.0前
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [pool release]; // [pool drain];
• iOS 5.0 开始
@autoreleasepool {
}

Autoreleasepool 的 实现
autorelease
是一种支持引用计数的内存管理方式 它可以暂时的保存某个对象(object),然后在内存池自己的排干(drain)的时候对其中的每个 对象发送release消息 注意,这里只是发送release消息,如果当时的引用计数(reference-counted)依然不为0,则该 对象依然不会被释放。可以用该方法来保存某个对象,也要注意保存之后要释放该对象。
2、为什么会有autorelease?
OC的内存管理机制中比较重要的一条规律是:谁申请,谁释放 考虑这种情况,如果一个方法需要返回一个新建的对象,该对象何时释放? 方法内部是不会写release来释放对象的,因为这样做会将对象立即释放而返回一个空对象;调用 者也不会主动释放该对象的,因为调用者遵循“谁申请,谁释放”的原则。那么这个时候,就发 生了内存泄露。
不使用autorelease存在的问题
针对这种情况,Objective-C的设计了autorelease,既能确保对象能正确释放,又能返回有效的 对象。

3、autorelease是什么原理?
autorelease实际上只是把对release的调用延迟了,对于每一个Autorelease,系统只是把该 Object放入了当 前的Autorelease pool中,当该pool被释放时,该pool中的所有Object会被调用 Release。
4、autorelease何时释放?
对于autorelease pool本身,会在如下两个条件发生时候被释放(详细信息请参见第5条) 1)手动释放Autorelease pool
2)Runloop结束后自动释放
对于autorelease pool内部的对象
在引用计数的retain == 0的时候释放。release和autorelease pool 的 drain都会触发retain– 事件。

5、autorelease释放的具体原理是什么?
要搞懂具体原理,则要先要搞清楚autorelease何时会创建。 我们的程序在main()调用的时候会自动调用一个autorelease,然后在每一个Runloop, 系统会隐 式创建一个Autorelease pool,这样所有的release pool会构成一个象CallStack一样的一个栈式 结构,在每一个Runloop结束时,当前栈顶的 Autorelease pool(main()里的autorelease)会被 销毁,这样这个pool里的每个Object会被release。
可以把autorelease pool理解成一个类似父类与子类的关系,main()创建了父类,每个Runloop自 动生成的或者开发者自定义的autorelease pool都会成为该父类的子类。当父类被释放的时候, 没有被释放的子类也会被释放,这样所有子类中的对象也会收到release消息。 那什么是一个Runloop呢? 一个UI事件,Timer call, delegate call, 一个鼠标事件,键盘按 下(MAC OSX),或者iphone上的触摸事件,异步http连接下后当接收完数据时,都会是一个新的 Runloop。 一般来说,消息循环运行一次是毫秒级甚至微秒级的,因此autorelease的效率仍然是非常高的, 确实是一个巧妙的设计。

autorelease的常见错误
• alloc之后调用了autorelease,又调用release
Person *p = [[[Person alloc] init] autorelease];
[p release];
• 连续调用多次autorelease
Person *p = [[[[Person alloc] init] autorelease] autorelease];

autorelease和release使用对比

• 使用release
Book *book = [[Book alloc] init];
[book release];
• 使用autorelease
Book *book = [[[Book alloc] init] autorelease];
// 不要再调用[book release];

autorelease的应用场合
• 一般可以为类添加一个快速创建对象的类方法
+ (id)book {
return [[[self alloc] init] autorelease];
}
外界调用[Book book]就可以获得和使用新建的Book对象,根本不用考虑在什么时候释放Book对象
• 一般来说,除了alloc、new或copy之外的方法创建的对象都被声明了autorelease
• 比如下面的对象都已经是autorelease的,不需要再release
NSNumber *n = [NSNumber numberWithInt:100];
NSString *s = [NSString stringWithFormat:@”jack”];
NSString *s2 = @”rose”;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值