孩子失去了对父母的弱引用

时间:2013-12-17 01:07:30

标签: ios objective-c automatic-ref-counting

我有一个AMContact对象,其中一个强属性是AMEmailAddress对象的数组。一个联系人可以有许多电子邮件地址我可以在指向联系人对象的电子邮件地址对象上创建一个强大的属性吗?

我觉得如果它的强引用可能会有一个保留周期。如果我使它变弱,当我进行查询以获取所有电子邮件地址对象时,在某些时候,每个对象的联系对象都将变为零。

- (NSArray*)allEmailAddresses
{
    NSArray *allContacts = [self allContacts];
    NSMutableArray *emailAddresses = [NSMutableArray array];

    for (AMContact *contact in allContacts) {
        if (contact.emailAddresses) {
            for (AMEmailAddress *address in contact.emailAddresses) {
                [emailAddresses addObject:address];
            }
        }
    }
    if (emailAddresses.count > 0) {
        return emailAddresses;
    }
    return nil;
} 


@interface AMContact : NSObject

@property (nonatomic, strong) NSString *firstName;
@property (nonatomic, strong) NSString *lastName;


// arrays of AMEmailAddress, AMPhoneNumber objects
@property (nonatomic, strong) NSArray *emailAddresses;
@property (nonatomic, strong) NSArray *phoneNumbers;

@end

@interface AMEmailAddress : NSObject

@property (nonatomic, strong) NSString *label;
@property (nonatomic, strong) NSString *email;
@property (nonatomic, strong) AMContact *contact; // IS THIS OK OR A RETAIN CYCLE?

@end

2 个答案:

答案 0 :(得分:2)

简短回答您的问题:我可以在指向联系人对象的电子邮件地址对象上创建强大的属性吗?

你能吗?是。你应该?绝对不。您的模型设计已经暗示了关系应该是什么 - AMContact对象拥有电子邮件地址,而不是相反。拥有电子邮件地址强烈引用父对象不是一个很好的方法来解决这个问题。从孩子回到所有者的引用应该是弱的。您的AMContact实例将变为零的事实是范围和设计的问题,您不应该使用强引用来解决这个问题。

至于为什么你的AMContact实例为零 - 这有点奇怪,因为如果AMContact对象变为nil,它的子对象也应该如此。它在您发布的代码中是否为零,或者在某些其他方法中的其他位置?看到你试图引用它的代码,它是零,会很好。

更新:

如果您想要一个包含电子邮件地址的联系人列表,您应该更改该方法以返回该地址。但是,我猜你的意思是你想要一个他们的电子邮件地址列表及其相关的联系人。在这种情况下,您必须翻转关系,并将电子邮件视为父母,将联系人视为孩子。请注意,如果联系人有多个电子邮件地址,那么您将拥有对同一联系人的多个引用。假设您的contact对象中有AMContact类型的AMEmailAddress属性,我会按如下方式添加一行:

for (AMEmailAddress *address in contact.emailAddresses) {

            //Assign the contact as a property of the email address
            //Make sure the contact property is strong
            address.contact = contact;

            [emailAddresses addObject:address];
        }

 //Nil out the emailAddresses array
 contact.emailAddresses = nil;

更新:

好的,现在你应该有一个翻转的对象 - emailAddress作为父对象,contact作为孩子,不再有contactemailAddress的强引用。这意味着您将无法再次使用contact对象来获取电子邮件地址。如果你需要保持原始的contact对象,那么你是对的,你必须将它作为一个属性存储在View Controller或另一个类中 - 对于这样的方法我需要处理与人物对象(允许用户邀请朋友等)我使用“人物管理器”单例并保留所有原始对象。

答案 1 :(得分:0)

在你的情况下,我认为很明显联系人是他的电子邮件地址的所有者(父母),因此你可以通过这种方式设计这种关系来避免任何周期,即使用弱引用回到联系人。如果您使用强引用,那么您将有一个保留周期,因为NSArray会将其保留在emailAdresses中。

现在,我会检查你的程序结构,看看你在弱引用中失去联系的方式和原因,必须释放它们,或许,你的联系人过早地留下了范围?

您可以在此great article中获取有关保留周期的更多信息和建议,还有一些解决方法,但我建议您坚持使用更有意义的设计。