ObjectC语言基础3—内存管理、引用计数器、@property、模型


一、内存管理根源

1、任何继承了NSObject对象都需要做内存管理。栈空间的东西自动回收,而堆空间的不会,对象存在堆空间,需要手动回收。


二、引用计数器

1、怎样判断何时回收,每一个OC对象都有自己的整型引用计数器,表示对象被引用的次数。

2、当使用allco(init对计数器没影响,它不是分配内存,是初始化)copy,new创建一个新对象时,对象的引用计数器默认值为1,当对象的引用计数器为零时,就会被系统自动回收。给对象发送一个retain消息计数器加1,给对象发送一个release消息计数器减1,还可以调用retainCount消息获取当前引用计数器的值。main函数有一个循环,只要不返回程序就不退出。

3、僵尸对象只的是所占用内存已经被回收,不能再被使用。野指针是指向僵尸对象的指针。空指针是没有指向任何地方的指针。

[java]  view plai
  1. Person *p = [[Person alloc] init];
  2. [p release];//有alloc必需有release
  3. p=null;//防止野指针错误

  4. [p retain];//计数器加一,返回对象本身
  5. [p release];
  6. p = null;//防止野指针错误,在OC里面给一个空指针发送消息时不会报错的。

  7. //有retain必需有release。release必须成对出现,否则会出现野指针错误,当对象已经释放,但指针依然指向这块内存
  8. //继续访问这块内存将会报错,EXC_BAD_ACESS指针反问一块不可用的内存。

  9. //对象在销毁时会自动调用delloc
  10. - (void) dealloc
  11. {
  12. //dealloc方法,一定要调用,并且要放在最后。
  13. [super dealloc];
  14. }


三、多对象内存管理

1、当你想拥有某个对象时,应该对对象计数器retain,有加必有减,当不使用时release。

2、当使用allco(init对计数器没影响,它不是分配内存,是初始化)copy,new创建一个新对象时,对象的引用计数器默认值为1,当对象的引用计数器为零时,就会被系统自动回收。

[java]  view plai
  1. //Person类里面包含一本书
  2. @interface Person :NSObject
  3. {
  4. Book *_book;//再定义属性时要以下划线开头
  5. }
  6. - (void)setBook:(Book *)book;
  7. -(Book *)book;
  8. @end
  9. @implementation Person
  10. - (void)setBook:(Book *)book{
  11. //如果重复设置相同对象,不做任何操作
  12. if(_book == book){
  13. //对当前进行使用的对象进行release。对NULL对象release没关系
  14. [_book release];
  15. //把成员变量对象引用计数加一
  16. _book = [book retain];//retain对象返回的事对象本身
  17. }
  18. }
  19. - (Book *)book{
  20. return _book;
  21. }
  22. - (void)dealloc
  23. {
  24. //在person对象销毁的时候会自动调用该方法,这是应该对Book对象进行release
  25. [_book release];
  26. [super dealloc];//调用父类方法,放在最后
  27. }

  28. @end
  29. int main(){
  30. Person *p = [[Person alloc] init];
  31. Book *b = [[Book alloc] init];
  32. [p setBook:b];//这个时候这本书的引用应该2。set方法里应该自动给引用计数retain
  33. b = null;
  34. [b release];//有alloc就必须有release;谁创建谁release
  35. p = null;
  36. [p release];
  37. }
  38. Person *p = [[Person alloc] init];
  39. [p release];//有alloc必需有release
  40. p=null;//防止野指针错误

  41. [p retain];//计数器

3、@property属性会自动生成get方法和set方法。
[java]  view plai
  1. //@property会自动生成get和set方法,成员变量会以下划线开头,同时也可以自己实现get或set方法
  2. @property (monatomic ,retain) Book *book
  3. //retain方法就会自动在set方法里面添加如下代码,但是dealloc方法还是要自己写
  4. (void) setBook:(Book *)book{
  5. if(_book != book){
  6. [_book release];
  7. _book = [book retain];
  8. }
  9. }
  10. (void) dealloc{
  11. [_book release];
  12. [super dealloc];
  13. }
  14. //解决方法,1@property ,2重写dealloc方法


4、@property参数类别,可分为
1>内存管理相关参数。retian会release旧值,retian新值。默认为assign是直接赋值,适用于非OC对象类型。copy 用于NSString
2>是否生产set方法。readonly只读,默认readwrite。
3>多线程管理。nonatomic,默认atomic,性能高。
4>set和get方法的名称。取方法名 set= setBook:  方法名后要有冒号。

5、循环引用
1、一个人里面有个身份证属性,一个身份证类有个人属性。在头文件中用@class声明成员变量是一个类,在.m文件中真的用到这个类的对象的方法时在引用#import。
2、开发中引用一个类的规范,在.h方法中@class声明一个类,在.m文件中用#import文件。
3、1@class可以解决循环引用,2效率高,#import是拷贝会包含被引用类的所有信息,使用#import会降低编译效率,如果一个文件改变了,后面的文件需要重新编译,降低编译效率,@class不会。
4、循环引用的解决办法,一端用assign,一端用retain
[java]  view plai
  1. //person
  2. @class Card
  3. @interface Perosn :NSObject
  4. @proterty (noatomic, assign) Card *card;
  5. @end

  6. #import "Card.h"
  7. @implementation Person
  8. -(void) dealloc{
  9. [super dealloc];
  10. }
  11. @end

  12. //card
  13. @class Person
  14. @interface Card:NSObject
  15. @property (noatomic,retain) Person *person;
  16. @end

  17. @implementatin Card
  18. -(void) delloc{
  19. [_person relase]; 
  20. [super dealloc];
  21. }
  22. @end

  23. //
  24. int main()
  25. {
  26. Person *p = [[Person alloc] init];
  27. Card *c = [[Card card] init];
  28. p.card = c;//循环引用
  29. c.person = p
  30. [p release];
  31. [c release];
  32. }

5、autorelease方法
1、autorelease是半自动释放,autorelease方法会返回对象本身,autorelease会将对象放大自动释放池中,当池子销毁时,会对池中对象进行release。
2、放到池子内的对象不允许再进行release操作。 不可以对对象联系调用两次autorelease方法,这样池子销毁时会调用两次release,出现野指针错误。
3、当子类继

[java]  view plai
  1. @autoreleasepool{//好处是不需要care对对象的release操作,并且对对象的操作一定要放在对对象操作的前面,缺点时不能精确控制对象的释放时间。最好显示调用retian release

  2. //对象的autorelease方法,会将对象放到池子里,不会对对象计数器的值进行改变
  3. Person *p = [[[Person alloc] init] autoreleas];//autorelease方法已定要写
  4. p.age =0;
  5. //[p release];如果不用autorelease,设置年龄的操作已定要在这一行前,如果在这一样后,就会出现野指针错误,autoreleas则不会

  6. @autoreleasepool{//对象池可以循环嵌套
  7. Person *p2 = [[[Person alloc] init] autoreleas];
  8. p2.age = 10;
  9. }

  10. }
  11. //实例,为了避免在每次创建一个对象都写autoreleas方法,可以在类里写一个类方法返回放在释放池中的对象
  12. +(id)person{
  13. return [[[Person(如果这里写self代码可扩展性好) alloc] init] autorelease];
  14. }
  15. //当子类继承父类的方法时,即拥有负累的所有方法和属性,但父类的方法可能不满足子类的要求,如上面返回的事一个person对象
  16. //可是子类不可能也是person对象,子类一会扩冲自己的属性,当你调用这个父类对象访问子类的属性时,父类没有
  17. //就会报不能识别的消息发送给某个对象,解决方法:1重写父类方法,2要实现谁调用这个方法我就返回谁,把Person改成self
  18. //同时还可以给对象设置一些属性值
  19. + (id)personWithAge:(int)age{
  20. Person *p = [[[Person alloc] init] autorelease];
  21. p.age = 10;
  22. return p ;
  23. }


三、模型类
用来存数据的类,称为模型类,写完属性,实现get,set方法,注意释放对象存储空间。如果使用@property,需要重写dealloc方法,release成员对象。
不一定要重写init方法。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值