Objective-C 属性无限循环

3

我目前正在学习Objective-C,这也是我第一次涉足编程,请多多包涵。

我有一个简单的对象叫做XYZPerson,它保存一个人的名字、姓氏和他或她伴侣的引用,伴侣也是一个XYZPerson对象。

以下是我在XYZPerson的头文件中声明的内容:

@interface XYZPerson : NSObject

@property (nonatomic, copy) NSString *firstName;
@property (nonatomic, copy) NSString *lastName;
@property (nonatomic, weak) XYZPerson *partner;

@end

在实现中,我写了这个:

- (void)setPartner:(XYZPerson *)aPartner
{
    _partner = aPartner;
    aPartner.partner = self;
}

但是在main()函数中,每当我调用personMale.partner = personFemale;时,它会创建一个无限循环。

我认为我知道原因了(因为aPartner.partner调用setPartner,而setPartner又会调用自己),但我找不到一个优雅的解决方案来解决这个问题。

任何帮助 - 包括如何工作的解释 - 都将不胜感激!

非常感谢!


2
你不应该在“初次涉足编程”时使用Objective-C。 - Hot Licks
3个回答

5
问题在于这行代码:“


aPartner.partner = self;

您可能没有意识到的是:它仅仅是调用setPartner:的简写。设置属性会调用相应的setter方法;事实上,这就是属性的全部含义,即通过调用setter/getter方法来操作!

但是,这行代码位于setPartner:的实现中。因此,您现在陷入了无限递归的状态:您正在不断地调用自己。这就像您说:

- (void)setPartner:(XYZPerson *)aPartner
{
    _partner = aPartner;
    [aPartner setPartner: self];
}

这里的所有XYZ人都是相同的,因此显然是一种递归。

毕竟,你不会说这句话:

- (void)setPartner:(XYZPerson *)aPartner
{
    [self setPartner: = aPartner];
}

但实际上这正是你所说的内容!

当你在setter方法中时,出于这个原因,你绝不能调用setter方法;你应该只引用底层的实例变量:

- (void)setPartner:(XYZPerson *)aPartner
{
    self->_partner = aPartner;
    aPartner->_partner = self;
}

1
在您的setter中,仅在伴侣发生更改时进行赋值:
- (void)setPartner:(XYZPerson *)aPartner
{
    if(_partner != aPartner) {
        _partner = aPartner;
        aPartner.partner = self;
    }
}

另一种解决方案是创建一个单独的方法来将两个人设为合作伙伴。
- (void)makePartner:(XYZPerson *)aPartner {
        self.partner = aPartner;
        aPartner.partner = self;
}

1
当你在一个XYZPerson上调用setPartner时,会发生什么呢?
假设你这样说:
XYZPerson *a = [[XYZPerson alloc] init];
XYZPerson *b = [[XYZPerson alloc] init];

a.partner=b;

在a的setPartner方法中,它将其partner属性设置为另一个人(b),然后调用person b的setPartner方法。
好的,现在person b的setPartner方法被触发了。在该方法中,它设置自己的partner属性,然后告诉它的新伴侣(person a)将其partner属性设置为自身(person b),这将再次调用person a的setPartner方法,如此循环,无限循环。(永远)
您可以使用if语句打破循环:
- (void)setPartner:(XYZPerson *)aPartner
{
    if (_partner != aPartner)
    {
        _partner = aPartner;
        aPartner.partner = self;
    }
}

现在,使用修改后的代码,序列将会是:
a.partner = b;

person的a的partner属性为nil,所以将其设置为b,然后调用b的setPartner方法。

在person b的setPartner方法中,它的partner也是nil,所以person b将其partner属性设置为person a,然后再次调用person a的setPartner方法。

然而,这一次person a的partner属性已经指向了person b,所以if语句的评估结果为false,该方法不执行任何操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接