【问题标题】:Why does initWithCoder need self.property?为什么 initWithCoder 需要 self.property?
【发布时间】:2023-03-26 03:25:01
【问题描述】:

在访问变量时,我倾向于在我的 Objective C 代码中经常使用 self.property,因为我知道这会使用 getter/setter 方法(显式编码或自动生成)。

另一位程序员最近告诉我,最好在整个代码中使用 _property。但我的理解是 _property 真的只用于 init 和 dealloc 方法。

今天我在一些使用 initWithCoder 的代码中发现了一个错误。我在 initWithCoder 方法中使用了 _property,不得不将其更改为 self.property。这是在设置 NSData 对象时。这是原始代码:

@property (nonatomic, strong) NSData *data;

- (id)initWithCoder:(NSCoder *)decoder {
    self = [super init];
    if (!self) {
        return nil;
    }
    _data = [decoder decodeObjectForKey:@"data"];
    return self;
}

我不得不把它改成这样,才能让它工作:

@property (nonatomic, strong) NSData *data;

- (id)initWithCoder:(NSCoder *)decoder {
    self = [super init];
    if (!self) {
        return nil;
    }
    self.data = [decoder decodeObjectForKey:@"data"];
    return self;
}

我的问题是 - 为什么 initWithCoder 是例外?如果普遍认为最好在 init 方法中使用 _property,那么为什么 initWithCoder 会有所不同?

现在看来,一般规则是:

使用 self.property,除了 init/dealloc 方法,应该使用 _property(除了 initWithCoder,应该使用 self.property)。

这是正确的吗?

【问题讨论】:

  • 我看不出为什么在initWithCoder: 中你的代码self.property 会在_property 不起作用时起作用。 self.property 使用此属性的 setter 来初始化它是正确的,而 _property 并没有绕道而行,而是初始化了 instance 变量 直接属于你的财产......这看起来很奇怪:/
  • 当你说“让它工作”时,你遇到了什么错误。我认为原始的基于 ivar 的 init 没有问题。告诉你只使用 ivars 的 coder 是不正确的;这不是最佳做法。曾经有一段时间在 ObjC 社区中存在更多分歧,但 Apple 终于记录了您应该使用除 init 和 dealloc 之外的访问器。
  • 我刚刚做了一个测试,它适用于_dataself.data。你的目标是什么版本的 iOS?更早的版本不会为属性data 自动生成_data 变量。
  • 从initWithCoder返回时出现错误,而不是在initWithCoder中。我在 initWithCoder 中放了一个断点,对 _data 的分配没问题。问题发生在 [NSKeyedUnarchiver unarchiveObjectWithFile:cachePathForKey]; 之后陈述。当它从这里返回时,该对象包含垃圾,除非我使用 self.data 而不是 _data
  • 应用的部署目标是7.0

标签: objective-c getter-setter initwithcoder


【解决方案1】:

我认为您通常不必使用initWithCoder: 中的属性。我有很多代码(并且已经看到很多)在initWithCoder: 中使用了 ivar 访问权限,如果这可能会有所帮助。

如果您没有使用 ARC,那么您的实现设置 _data 会出现问题,因为该对象很快就会自动关联。但在 ARC 下,您的代码是正确的。

所以,我倾向于认为是一些不同的东西导致了你的问题。例如,如果你使用 KVO,那么你应该使用属性,否则不会生成与 KVO 相关的通知。您应该提供更多信息,说明究竟是什么让您认为分配给 _data 是问题的原因,以及该问题在代码其他部分的可见影响。

【讨论】:

  • 这很奇怪。我检查了应用程序,它正在使用 ARC。我查看了构建阶段中的所有模块,没有一个设置为非 ARC。让我认为是 _data 使用的原因是,只需将该行更改为 self.data 即可使应用程序正常工作。否则,应用程序在 [NSKeyedUnarchiver unarchiveObjectWithFile:cachePathForKey] 之后立即崩溃;声明,当我尝试对数据做某事时。在 initWithCoder 中不会崩溃,从 NSKeyedUnarchiver 语句返回后会崩溃。
  • 你会遇到什么样的崩溃?你能从控制台发布崩溃日志吗?当你说它“之后”崩溃时,你的意思是它没有进入下一个语句吗?完整的unarchiveObjectWithFile 是什么样的?
  • 看起来这是对象在从 unarchiveObjectWithFile 返回时释放的问题。当我使用 MyCachedObject *tmp = [NSKeyedUnarchiver unarchiveObjectWithFile:cachePathForKey] 创建对象时;它崩溃了。但是,如果我分配对象然后调用 unarchiveObjectWithFile,像这样: MyCachedObject *tmp = [[MyCachedObject alloc] init]; tmp = [NSKeyedUnarchiver unarchiveObjectWithFile:cachePathForKey];有用。似乎对象在调用返回时没有被保留。
  • 这是一个有趣的发现。在MyCachedObject *tmp = [NSKeyedUnarchiver … 之后你的方法是如何进行的,这可能解释了正在发生的事情。再次,抱歉要求很高,崩溃信息是什么?这也可以帮助...
  • 是的,消息是 EXC_BAD_ACCESS(代码=1,地址=0xe000000c)。这似乎是过度释放的问题,并且很可能与应用程序中的其他内容有关,但是使用 self.property 而不是 _property 会导致对象被保留似乎很有趣。如果我不使用 ARC,它看起来就不那么神秘了。
猜你喜欢
  • 1970-01-01
  • 2019-06-09
  • 1970-01-01
  • 2020-05-03
  • 2020-03-22
  • 2011-08-11
  • 2019-06-09
  • 2012-05-21
  • 2020-02-26
相关资源
最近更新 更多