【问题标题】:Child losing its weak reference to parent孩子失去了对父母的弱参考
【发布时间】:2023-03-18 13:55:01
【问题描述】:

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

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

- (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

【问题讨论】:

  • 您说“在某些时候,每个联系人的联系人对象都变为零了”——这究竟是什么时候发生的?在您发布的部分代码中还是在其他方法中?

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


【解决方案1】:

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

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

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

更新:

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

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 或另一个类中 - 对于像这样的方法,我必须与人打交道对象(用于允许用户邀请朋友等)我使用“人员管理器”单例并将所有原始对象保留在那里。

【讨论】:

  • 感谢您的回答。我认为 allEmailAddresses 方法中发生的事情是我正在获取所有联系人的数组,找到带有电子邮件的联系人,然后只保存并返回电子邮件对象。没有人保留这个原始的联系人数组,这一定是为什么它会为零。我该如何预防?
  • 更新的答案 - 让我知道这是否是您正在寻找的内容
  • 谢谢。在这种情况下它会起作用,但其他时候我需要联系人成为我出售的对象。所以在那种情况下,我的电子邮件地址数组是一个弱属性似乎不起作用。我尝试过的一个解决方案是将联系人数组出售给视图控制器,在属性中保留对它的引用,然后使用与上述相同的例程获取我的电子邮件对象。这是有效的,因为有人正在维护对联系人对象的强引用。缺点是它们占用了一些我不想使用的内存。这是一个好的设计吗?
  • 当您说“我需要联系人成为我出售的对象”时 - 您的意思是联系人应该是您的 allContacts 方法返回的联系人?如果是这样,那么它们就是相同的对象,因为我们只是在传递引用。但是,您将不得不翻转关系 - 即,一旦您完成它,就将 AMContact 对象的 emailAddresses 数组归零。我会更新上面的代码。
  • 好的,我现在有一个可行的设计。感谢您的所有帮助。人事经理类型的方法是要走的路。
【解决方案2】:

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

现在,我会检查你的程序结构,看看你是如何以及为什么在那个弱引用中失去联系的,一定是有什么东西释放了他们,也许,你的联系过早地离开了范围?

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-10
    • 2019-05-09
    相关资源
    最近更新 更多