一个简单的问题。
如果我有一个属性和一个用相同名称声明的ivar:
<。>文件中的:
(Reminder*)reminder;
@property(nonatomic,strong)(Reminder*)reminder;
<。>在.m文件中,如果我使用ARC,我应该在init方法中使用ivar还是属性?
- (id)initWithReminder:(Reminder*)reminder_ {
self = [super init];
if (self) {
reminder = reminder_;
}
return self;
}
或者我应该使用该属性来获得自动引用计数的好处,如下所示:
- (id)initWithReminder:(Reminder*)reminder_ {
self = [super init];
if (self) {
self.reminder = reminder_;
}
return self;
}
我不确定在对象的初始化中哪个点可以通过点表示法访问属性。
答案 0 :(得分:67)
在部分构造的状态下使用直接访问,无论ARC如何:
- (id)initWithReminder:(Reminder*)reminder_ {
self = [super init];
if (self) {
reminder = reminder_;
// OR
reminder = [reminder_ retain];
}
return self;
}
这是因为self.whatever
会触发其他副作用,例如键值观察(KVO)通知,或者您的类实现(显式)或子类覆盖setWhatever:
- 这可能将部分初始化的实例暴露给其他API(包括它自己的),这正确地假设它们正在处理完全构造的对象。
您可以手动验证某个类是否能够在部分初始化状态下运行,但这需要大量维护,并且(当然)当其他人想要为您的类创建子类时,这是不切实际或不可能的。它需要大量的时间和维护,并且没有这样做的实质性好处,特别是如果您尝试将该方法用作约定。
因此,保证正确性的统一方式是在部分构造的状态下使用直接访问,并避免使用访问器。
注意:我正在使用“部分构造”,因为初始化只是图片的一半; -dealloc
也有类似的警告。
有关在部分构建状态(ARC || MRC)中使用直接访问的原因的更多详细信息,请访问:Initializing a property, dot notation
答案 1 :(得分:5)
答案 2 :(得分:0)
我不确定在对象的初始化中哪个点可以通过点表示法访问属性。
由于点符号仍然是Objective-C方法(以及实际上在ObjC方法下的C方法),点符号或调用方法是完全安全的GIVEN该方法准备处理基础类型在他们恰好处于的任何状态的记忆中。 关于避免使用未经过处理的(可能的)车库存储器段的正常规则仍然适用。这是在初始化中使用ivar的最强烈动机。
但是如果你的方法(getter | setter)能够正确使用内存段 - 无论是在读取之前是否首次写入 - 那么一定要在init方法中使用你的getter。 懒惰的getter利用了它初始化的指针开始为'nil'来决定执行初始化的假设。如果你不能假设你的记忆的初始内容,那么初始化ivar可能是最安全的课程。
如果方法在这种情况下能够正确运行,为什么在init中永远不会使用setter或getter的规则?