Objective - C基础: 第五天 - 6.循环引用
来源:互联网 发布:杭州学淘宝哪家比较好 编辑:程序博客网 时间:2024/06/15 03:29
在前面, 我们知道了OC的内存管理以及@property的参数, 其实还有一个叫做循环引用, 其实所谓的循环引用很简单, 就是两个类中, 你包含我, 我包含你, 这个就叫循环引用, 比如下面这个例子:
#import <Foundation/Foundation.h>#import "Car.h"@interface Person : NSObject@property (nonatomic, retain) Car *car;@end
#import <Foundation/Foundation.h>#import "Person.h"@interface Car : NSObject@property (nonatomic, retain)Person *person;@end
这样子就是循环引用, 但这个例子里的循环引用是有性能问题的, 需要改进, 我们来看看改进之后的例子:
#import <Foundation/Foundation.h>@class Car;@interface Person : NSObject@property (nonatomic, retain) Car *car;@end
#import <Foundation/Foundation.h>@class Person;@interface Car : NSObject@property (nonatomic, retain)Person *person;@end
为什么这么做呢? 我们来回想一下, #import的作用就是引用头文件, 如果在我们平常的简单编程里面, 直接这么做是没问题的, 但如果在几十个几百个类中循环引用, 一旦某个被循环引用的类修改了一点点, 那么全部引用它的类就要重新再引用, 就会造成性能问题, 所以我们这里使用@class.
@class的作用仅仅只是告诉编译器XXX是一个类, 我们可以使用, 不像#import那样直接引用, 但@class也并不是完美的, 如果我们使用手动引用计数, 需要在.m文件里release对象的话, 那么就需要使用到#import来辅助一下, 比如:
#import "Person.h"#import "Car.h"@implementation Person- (void)dealloc{ [_car release]; [super dealloc];}@end
#import "Car.h"#import "Person.h"@implementation Car- (void)dealloc{ [_person release]; [super dealloc];}@end
那么@class和#import的区别在哪里? 我们来看看区别:
#improt 方法会包含被引用类的所有信息, 包括被引用类的变量和方法;
@class 方式只是告诉编译器在X.h文件中X *x只是类的声明, 具体这个类里面有什么信息, 这里不需要知道, 等实现文件中真正要用到时, 才会真正去查看X类中信息
总结
1. 如果有上百个头文件都#import了同一个文件, 或者这些文件一次被#import, 那么一旦最开始的文件稍有改动, 后面引用到这个文件的所有类都需要重新编译一边, 这样的效率可想而知, 而相对来讲, 使用@class方式就不会出现这种问题了.
2. 在.m实现文件中, 如果需要引用到被引用类的实例变量或者方法时, 还需要使用#import方法引入被引用类.
再回头看看我们的例子, 我们会发现, 该例子会有循环retain, 什么是循环retain呢? 其实循环retain一般只会出现在循环引用上, 当两个类相互引用并且使用retain的时候, 那么谁也不会被释放, 这样子就会造成内存泄漏, 比如:
#import <Foundation/Foundation.h>#import "Person.h"#import "Car.h"int main(int argc, const char * argv[]){ Person *p = [[Person alloc] init]; Car *c = [[Car alloc] init]; p.car = c; c.person = p; NSLog(@"p = %ld", [p retainCount]); NSLog(@"c = %ld", [c retainCount]); [c release]; [p release]; return 0;}
打印出来的结果:
2015-01-27 12:23:23.885 07.循环引用[6274:661345] p = 22015-01-27 12:23:23.886 07.循环引用[6274:661345] c = 2
有人会想到, 简单啦, 直接写两次release就可以啦, 没错是可以这么做, 但这么做不符合apple的内存管理原则, 我们之前说过内存管理的原则是一次alloc一次release, 所以该做法不可取.
解决办法其实也很简单, 只要把其中一个类改成assign就可以解决了, 比如:
#import <Foundation/Foundation.h>@class Car;@interface Person : NSObject@property (nonatomic, assign) Car *car;@end
#import <Foundation/Foundation.h>@class Person;@interface Car : NSObject@property (nonatomic, retain)Person *person;@end
在看看main()函数打印出来的结果:
2015-01-27 12:27:19.038 07.循环引用[6316:663154] p = 22015-01-27 12:27:19.039 07.循环引用[6316:663154] c = 12015-01-27 12:27:19.039 07.循环引用[6316:663154] Car被释放了2015-01-27 12:27:19.039 07.循环引用[6316:663154] Person被释放了
两端互相引用造成内存泄漏的解决方案: 把其中一端的retain改成assign.
好了, 这次我们就讲到这里, 下次我们继续~~
- Objective - C基础: 第五天 - 6.循环引用
- Objective - C基础: 第五天 - 1.计数器的基本认识
- Objective - C基础: 第五天 - 3.set方法内存管理
- Objective - C基础: 第五天 - 4.@property - 内存管理
- Objective - C基础: 第五天 - 5.@property - 参数详解
- Objective - C基础: 第五天 - 7.autorelease的基本认识
- Objective-c 循环引用
- Objective-C 循环引用
- Objective - C基础: 第六天 - 3.ARC循环引用
- 学习Objective-C--第五天
- objective-c 第五天 类 对象 方法
- Objective-C - 循环引用问题
- Objective - C基础: 第五天 - 2.多个对象之间的内存管理
- Effective Objective-C(第29-36条)内存管理篇,ARC、循环引用、引用计数
- Objective-C 10天学习_第五天
- Objective-C 10天学习_第五天
- 第五天(objective-c)(类和对象)
- Objective-C 循环引用的处理
- 解决费米悖论的一个猜想
- asp.net mvc3 简单的文件上传下载
- listview 下拉刷新加载数据
- Redis主从同步分析<转>
- C++内存管理
- Objective - C基础: 第五天 - 6.循环引用
- 通向码农的道路(运镖系统,推荐算法)
- C# 导出Word文档中的所有图片
- 将excel文件中的数据导入到mysql
- 最简单的使用MCV4网页进行文件上传
- C#继承中abstract、virtual、override和new
- android:parentActivityName
- 修改hosts文件访问Facebook、youtube、github、google等国外知名网站
- 注胶隔热型材加工过程中常见问题处理六、七