年年有"余"

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 44352|回复: 1

相互引用与相互retain

[复制链接]
  • TA的每日心情
    奋斗
    2022-12-13 21:26
  • 签到天数: 371 天

    [LV.9]以坛为家II

    发表于 2014-3-19 16:27:49 | 显示全部楼层 |阅读模式
    假设场景与说明:
    1、Person对象有个成员变量为Card对象,Card对象中有个成员变量为Person对象;
    2、Person对象将Card对象做为其成员变量,需要引入头文件"Card.h",同样Card对象将Person对象做为其成员变量,需要引入头文件"Person.h",那么两个头文件相互引用,会千万死循环,OC中通过使用#import替代C语言中的#include解决了多次引用的问题,但解决不了循环引用的问题,所以在这种情况下,通过@class Person或者@class Card来解决声明问题,至少要有一方使用该方法声明类,才能解决循环引用的问题;
    3、另外一个问题:相互retain,要常规模式下,一个对象做为另一个对象的成员变量,示意图如下所示:
    001.png


    4、Card对象做为Person对象的成员变量,创建并赋值给_card后,当前有两个拥有者,所以retainCount = 2,进行[c release]操作后,只有_card对其拥有所有权,如果Person对象执行release操作,同时会在dealloc方法中对_card进行release操作,这样对象成功释放,符合黄金法则,一切正常。
    5、但如果Card对象中同时也有一个_person对象对Person对象c也有拥有权,这样一来两个对象都无法被释放,先看示意图,再说明不能释放的关键点:
    002.png


    6、如果以Person为主,Card * c做为其成员对象,原则上创建好对象赋值给_card后,将临时变量c进行释放,但c同时又是另一个对象的主对象,因而Card * c在进行alloc操作分配存储空间后只会做一次release操作,不可能做两次release,可事实上,c在赋值给Person * p的成员变量_card时进行了一次retain操作,此时retainCount = 2;
    7、如果以Card为主,面临同样的问题,所在关键点在于,两个对象的retainCount值由于相互赋值时都增加了1,进行一次release后,不会调用dealloc方法,所以第二次release无法触发,从而两对象处于互等状态
    8、解决这个问题的办法:将其中一个对象在声明时@property (nonatomic, retain) 时,将retain改成assign,只修改其中一个即可,问题得以解决;

    参考代码:
    Person.h
    1. //
    2. //  Person.h
    3. //  Retain-1
    4. //
    5. //  Created by yusian on 14-3-19.
    6. //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    7. //
    8. #import <Foundation/Foundation.h>
    9. @class Card;
    10. @interface Person : NSObject
    11. @property (nonatomic, retain) Card *card;
    12. @end
    复制代码


    Person.m
    1. //
    2. //  Person.m
    3. //  Retain-1
    4. //
    5. //  Created by yusian on 14-3-19.
    6. //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    7. //
    8. #import "Person.h"
    9. @implementation Person
    10. - (void)dealloc
    11. {
    12.     NSLog(@"Person is dealloc...");
    13.    
    14.     [_card release];
    15.    
    16.     [super dealloc];
    17. }
    18. @end
    复制代码
    Card.h
    1. //
    2. //  Card.h
    3. //  Retain-1
    4. //
    5. //  Created by yusian on 14-3-19.
    6. //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    7. //
    8. #import <Foundation/Foundation.h>
    9. @class Person;
    10. @interface Card : NSObject
    11. @property (nonatomic, assign) Person * person;
    12. @end
    复制代码
    Card.m
    1. //
    2. //  Card.m
    3. //  Retain-1
    4. //
    5. //  Created by yusian on 14-3-19.
    6. //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    7. //
    8. #import "Card.h"
    9. @implementation Card
    10. - (void)dealloc
    11. {
    12.     NSLog(@"Card is dealloc...");
    13.    
    14.     //[_person release];
    15.    
    16.     [super dealloc];
    17. }
    18. @end
    复制代码
    main.m
    1. //
    2. //  main.m
    3. //  Retain-1
    4. //
    5. //  Created by yusian on 14-3-19.
    6. //  Copyright (c) 2014年 小龙虾论坛. All rights reserved.
    7. //
    8. #import <Foundation/Foundation.h>
    9. #import "Person.h"
    10. #import "Card.h"
    11. int main()
    12. {
    13.     Person * p = [[Person alloc] init];
    14.    
    15.     Card * c = [[Card alloc] init];
    16.    
    17.     p.card = c;
    18.    
    19.     c.person = p;
    20.    
    21.     [p release];
    22.     [c release];
    23.     return 0;
    24. }
    复制代码
    运行结果:
    2014-03-19 16:27:33.036 Retain-1[1709:303] Person is dealloc...
    2014-03-19 16:27:33.037 Retain-1[1709:303] Card is dealloc...
    Program ended with exit code: 0

  • TA的每日心情
    奋斗
    2022-12-13 21:26
  • 签到天数: 371 天

    [LV.9]以坛为家II

     楼主| 发表于 2014-3-20 00:06:46 | 显示全部楼层
    补充一句,声明文件(.h)中只声明了类@class Person,在实现文件(.m)中需要引用类的声明文件(.h),即在.m文件中#import Person.h
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    手机版|小黑屋|Archiver|iOS开发笔记 ( 湘ICP备14010846号 )

    GMT+8, 2024-5-2 21:16 , Processed in 0.047209 second(s), 22 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表