我应该在 ARC 的 init 方法中引用 self.property 吗?
一个简单的问题。
如果我有一个使用相同名称声明的属性和 ivar:
在 .h 文件中:
(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;
}
我不确定在对象初始化的哪个点可以使用点表示法访问属性。
A quick question.
if I have a property and an ivar declared with the same name:
in the .h file:
(Reminder*)reminder;
@property(nonatomic,strong)(Reminder*)reminder;
in the .m file, should I use the ivar or the property in the init method if I'm using ARC?
- (id)initWithReminder:(Reminder*)reminder_ {
self = [super init];
if (self) {
reminder = reminder_;
}
return self;
}
Or should I use the property to get the benefit of the automatic reference counting like this:
- (id)initWithReminder:(Reminder*)reminder_ {
self = [super init];
if (self) {
self.reminder = reminder_;
}
return self;
}
I'm not sure at which point in the object's initialization the properties become accessible with the dot notation.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
无论 ARC 如何,都在部分构造的状态下使用直接访问:
这是因为 self.whatever 会触发其他副作用,例如键值观察 (KVO) 通知,或者您的类可能(显式)实现或者子类重写 setWhatever: ,这可能会将部分初始化的实例暴露给其他 API(包括它自己的 API),这些 API 正确地假设它们正在处理完全构造的对象。
您可以手动验证一个类是否能够在部分初始化的状态下运行,但这需要大量维护,并且(坦率地说)当其他人想要对您的类进行子类化时,这是不切实际或不可能的。它需要大量的时间和维护,并且这样做没有实质性的好处,特别是如果您尝试使用该方法作为约定。
因此保证正确性的统一方式是在部分构造的状态下使用直接访问,并避免使用访问器。
注意:我使用“部分构造”,因为初始化只是图片的一半;
-dealloc
有类似的警告。关于为什么应该在部分构造状态(ARC || MRC)中使用直接访问的更多详细信息可以在这里找到:初始化属性,点符号
Use direct access in partially constructed states, regardless of ARC:
This is because
self.whatever
will trigger other side effects, such as Key-Value Observing (KVO) notifications, or maybe your class implements (explicitly) or a subclass overridessetWhatever:
-- and that could expose your partially initialized instance to other APIs (including its own), which rightly assume they are dealing with a fully constructed object.You could manually verify that a class is capable of operating in a partially initialized state, but that requires a lot maintenance and is (frankly) impractical or impossible when other people want to subclass your class. It requires a lot of time and maintenance, and there isn't substantiative benefit doing so, especially if you try to use the approach as a convention.
So the uniform manner which guarantees correctness is to use direct access in partially constructed states, and avoid using the accessors.
Note: I am using "partially constructed" because initialization is only half of the picture;
-dealloc
has similar caveats.Some more detail as to why you should use direct access in partially constructed states (ARC || MRC) can be found here: Initializing a property, dot notation
不,你不应该!
您可以在此处
找到原因说明
苹果也建议不要这样做。 在此处阅读
No you shouldn't!
You can find description why here
Also apple recommend to don't do it. Read here
由于点表示法仍然是 Objective-C 方法(实际上是 ObjC 方法下的 C 方法),因此点表示法或调用该方法是完全安全的,因为该方法已准备好处理内存中的底层类型无论他们碰巧处于什么状态。
关于避免使用未初始化(可能)的车库内存段的正常规则仍然适用。这是在 init 中使用 ivar 的最强烈动机。
但是,如果您的方法 (getter|setter) 能够正确使用内存段(无论它是否在读取之前先写入),那么请务必在 init 方法中使用您的 getter。
惰性 getter 利用这样的假设:它将初始化的指针以“nil”开头来决定执行初始化。如果您无法假设内存的初始内容,那么初始化 ivar 可能是最安全的方法。
如果该方法能够在这种情况下正确运行,为什么要制定从不在 init 中使用 setter 或 getter 的规则呢?
Since the dot notation is still an Objective-C method (and a C method actually under the ObjC method) the dot notation, or calling the method, is perfectly safe GIVEN the method is prepared to deal with underlying type(s) in memory in whatever state they happen to be in.
The normal rule about avoiding use of an uninitiatilized (possibly) garage memory segment still would apply. Which is the strongest motivation for use of the ivar in the init.
But if your method (getter|setter) is capable of correctly using the memory segment - independent of whether it is first written to before being read - then by all means use your getter in the init method.
A Lazy getter takes advantage of the assumption that a pointer it will initialize starts as 'nil' to decide on performing the initialization. If you cannot assume the initial contents of your memory then initializing the ivar might be the safest course.
Why have the rule of never using setters or getters in the init if the method is capable of operating correctly in this scenario?