【问题标题】:NSDate retain message sent to deallocated instanceNSDate 保留消息发送到解除分配的实例
【发布时间】:2011-03-24 23:21:28
【问题描述】:

我在使用 NSDate 并将其保存在 NSUserDefaults 中时遇到了一些问题。每次 NSUserDefaults 保存我的 NSDate 时,它​​似乎都无法保存,因为它已被释放并在日志中显示此错误。

-[__NSDate retain]: message sent to deallocated instance 0x4c20c80

我知道 NSDate 分配和释放的方式与普通对象不同,但我想知道是否有人知道是否使用:

- (void)saveData
{
NSUserDefaults *data = [NSUserDefaults standardUserDefaults];
[data setObject:dateOpened forKey:@"dateOpened"];
[dData synchronize];
}

...或...

- (void)loadData
{
NSUserDefaults *data = [NSUserDefaults standardUserDefaults];
dateOpened = [data objectForKey:@"dateOpened"];
}

我正在释放我的 NSDate 实例,因此将其保留计数设为 0,以便我的应用在尝试时无法再次保存它?

我正在使用:

@property (retain) NSDate *dateOpened;

任何想法都会非常感激,因为我正在努力解决这个问题。我只学习了大约 4 个月左右,并且几乎完成了我的第一个应用程序,这是工作中的主要扳手!

非常感谢,如果您需要更多代码或有关我正在做什么的信息,请告诉我。 :-D

【问题讨论】:

  • 在上面您保存和加载数据的示例代码中,ivar 说 CLOSED (dateClosed),键说 OPENED (dateOpened)。但是当您提到@property 行时,您会说ivar 是dateOpened (OPENED)。你是说你没有把约会搞混吗?
  • 哦,抱歉,忘记更改了。只是把它编辑成它应该是的样子。日期没有混淆,只是我的复制和粘贴错误。 :)

标签: iphone cocoa ios nsdate nsuserdefaults


【解决方案1】:

就内存管理而言,NSDate 的行为与任何其他对象没有任何不同。您可能指的是通常使用返回自动释放对象的便捷运算符(如 [NSDate date])(这意味着该对象将在主循环结束时(或每当释放自动释放池时)被删除,除非另一个类调用保留它。由于我看不到您的所有代码,我只能做出有根据的猜测,但我相信您正在对从 [data objectForKey:] 返回的对象调用 release,这将是您的错误。该函数返回一个自动释放的对象,因此在你调用retain之前你没有对象的“所有权”。如果你不调用retain,或者显式分配它,你不应该调用release它(这适用于所有对象)。

【讨论】:

  • 所以如果你想保留 NSDate 对象,就永远不应该调用 release 吗?另外,如果我完全没有保留 NSDate 的实例,我对您的理解是正确的,这与发布它一样糟糕吗?
  • 朋友,谢谢,谢谢,谢谢,谢谢!多年来,这一直让我发疯,现在我明白了。每次我得到日期时,我都只是输入 [NSDate date],所以没有保留它。因此,现在将其更改为 [[NSDate date] retain] 它会清除所有内容。谢谢你的帮助。 :-D
  • 欢迎您:)。如果你想保留一个对象,并保证它会在一个特定的类中存在,你应该始终保留它(通过在 init 调用中隐式调用或使用显式保留调用)。那么当这个类完成它时,它应该总是调用它的释放,这样它就不会被泄露。
【解决方案2】:

您遇到的问题在于您的 -loadData 方法。

dateOpened = [data objectForKey:@"dateOpened"];

是上面的那行,你是直接访问 ivar 而不是通过将保留的属性。所以你有两个选择之一。

// First choice retain it yourself
dateOpened = [data objectForKey:@"dateOpened"];
[dateOpened retain];

或者

// Second choice have the @property do it for you
[self setDateOpened:[data objectForKey:@"dateOpened"]];

这就是为什么在您的私有 ivars 上使用下划线是个好主意,这样您就可以知道何时直接访问它们。你会犯一些错误。 :)

// declaring it with underscore would have caught your mistake.
NSDate *_dateOpened;

【讨论】:

  • 添加下划线到底有什么作用?当我第一次收到 Xcode 4 时,我注意到它向我推荐了其他一些东西,但我真的不知道它在做什么......
  • 在“首选保留它自己”中,您还应该事先释放dateOpened,以防已经存在某些东西。此外,保留和分配可以在同一行完成:dateOpened = [[data objectForKey:@"dateOpened"] retain];
  • "在您的私有 ivars 上使用下划线,以便您知道何时直接访问它们。您不会出错。"这根本没有意义。您“知道”您正在访问一个属性,因为您在代码中写了一个点 (.);您“知道”您正在访问 ivar,因为您没有点。当您设置作为对象的 ivar(委托除外)时,您始终会保留/释放,即使您碰巧将该 ivar 用作属性。所以你看,它是否被用作属性是无关紧要的;只在设置实例变量时遵循要保留的规则很重要。
  • 是的,在适当的内存管理中,您会 [dataOpened release]。另外,如果您想对编码风格发表评论,则应直接针对问题。
【解决方案3】:

loadData 中的问题是你直接将dateOpened 赋值给一个自动释放的值,一旦事件循环通过,该值将无效。

- (void)loadData
{
NSUserDefaults *data = [NSUserDefaults standardUserDefaults];

// dateOpened = [data objectForKey:@"dateOpened"];

// try:
   self.dateOpened = [data objectForKey:@"dateOpened"];

// which is basically the same as:
// [self setDateOpened:[data objectForKey:@"dateOpened"]];

// the following 2 lines could also work:
// [dateOpened release];
// dateOpened = [[data objectForKey:@"dateOpened"] retain];

}

如果你有@synthesizeddateOpened,那么你可以想象你的类中添加了以下2个方法:

- (NSDate *)dateOpened {
  return dateOpened;
}

- (void)setDateOpened:(NSDate *)aDate {
  [aDate retain];
  [dateOpened release];
  dateOpened = aDate;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-11
    • 2013-06-04
    • 2012-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多