假设我有一个对象" dog"班级"狗"其属性可分为两组:
(A)在分配狗时必须初始化一次的属性;
(B)必须每隔一段时间重新初始化(重置)的属性;
所以我需要一种方法" resetB"它使用self重置组(B)中的属性,即
-(void) resetB {
self.propB1 = initValB1;
self.propB2 = initValB2;
self.propB3 = initValB3;
}
为了避免重复的代码(实际情况要复杂得多,有几十个属性),我想打电话给" resetB"来自我的" init",以便init wuold看起来像这样
-(id) init {
self = [super init];
if ( self ) {
propA1 = initValA1;
propA2 = initValA2;
propA3 = initValA3;
[self resetB];
}
return self;
}
好的,但现在我担心我会发短信" self"来自我的" init"方法,人们说被认为是......"不礼貌" ......(可以这么说) 我的问题是:我是否过分担心礼仪,如上所述实际上是安全的吗?或者,重复代码(必须保持同步)可能是较小的邪恶?或者还有另一个"正确"这样做的方式?
答案 0 :(得分:2)
当符合两个条件时,从self
向init
发送消息是安全的:
您调用的方法不会被派生类覆盖 - 在这种情况下,派生类实现将在对象完全初始化之前调用;
您没有设置属性,这可能会通过KVO触发对同一对象(仍未完全初始化)的某些操作。
如果您的reset
方法(与设置属性无关)是私有的,那么它应该没有问题,除非有人在派生类中定义了一个具有相同名称的方法。
为了进一步降低此风险,您可以为私有方法使用命名约定,例如_resetB
。
答案 1 :(得分:1)
我认为,当您调用属性设置器或其他方法时,self
内init
调用方法的唯一原因是有潜在危险 KVO可能引起副作用。
如果您知道该方法不会造成副作用,那么可以安全地拨打电话,并且调用常用的“安装方法”非常正常。来自多个版本的init
或来自awakeFromNib
等。
编辑正如@sergio所提到的,避免从self
调用init
上的方法的另一个原因是它可能会被未正确初始化的子类覆盖。另一种方法是将重置实现放入私有方法,该方法从init
调用,并且公共方法也使用私有方法。虽然私有方法也可以被覆盖,但显然不应该是:
@interface MyClass ()
- (void)_resetB;
@end
@implementation MyClass
-(id) init {
self = [super init];
if ( self ) {
_propA1 = initValA1;
_propA2 = initValA2;
_propA3 = initValA3;
[self _resetB];
}
return self;
}
- (void)resetB
{
[self _resetB];
}
#pragma mark - Private Methods
- (void)_resetB
{
_propB1 = initValB1;
_propB2 = initValB2;
_propB3 = initValB3;
}
@end