NSDate 内存管理使用 ARC Over Release

Posted

技术标签:

【中文标题】NSDate 内存管理使用 ARC Over Release【英文标题】:NSDate Memory Management Using ARC Over Release 【发布时间】:2013-09-20 19:34:09 【问题描述】:

我正在构建一个应用程序,其中使用标准视图控制器中的 UIDatePicker 设置 NSDate 对象。日期被添加到另一个类的可变字典中。当同一个类尝试访问日期对象时,它已经准备好被释放,导致崩溃。 此外,这只是在使用 Xcode 5 编译后才出现的问题。

示例代码

@interface SomeViewController ()

@property (nonatomic, strong) UIDatePicker *datePicker;
@property (nonatomic, strong) ChangeTracker *changeTracker; // Records local changes made to managed objects to send to server

@end

@implementation SomeViewController

// Relevant implementation
- (void)touchSetPicker:(UIButton *)sender

    [self setDate:self.datePicker.date forManagedObject:self.someManagedObject];


- (void)setDate:(NSDate *)date forManagedObject:(NSManagedObject *)managedObject

    // Set properties on managed object based on date param

    // Pass date to changeTracker class
    [self.changeTracker setDate:date forManagedObject:managedObject];

@end

ChangeTracker.m

@interface ChangeTracker ()

@property (nonatomic, strong) NSMutableDictionary *dateChanges;

@end

@implementation ChangeTracker

- (void)setDate:(NSDate *)date forManagedObject:(NSManagedObject *)managedObject

    NSString *idProperty = managedObject.idProperty;

    self.dateChanges[idProperty] = date;


- (void)compileAllChanges

    for (NSString *idProperty in [self.dateChanges allKeys]) 

        // Here is where the crash occurs due to the date being deallocated
        NSDate *date = self.dateChanges[idProperty];
    


@end

启用僵尸对象后,我收到错误消息: -[__NSDate release]: 消息发送到释放的实例

该项目正在使用 ARC,因此我无法明确尝试保留此对象。任何帮助将不胜感激。

【问题讨论】:

什么时候调用compileAllChanges? compileAllChanges 在按钮点击时从 ViewController 调用:[self.changeTracker compileAllChanges]; 【参考方案1】:

我遇到了@gabriel-ortega 描述的相同问题 我想知道他是否找到了解决问题的方法。

编辑:为了回答我自己并希望也能帮助其他人,我找到了问题的原因。

正如苹果文档所说:

为了允许与手动保留释放代码的互操作,ARC 对方法命名施加了限制:您不能为访问器指定以 new 开头的名称。这反过来意味着,例如,除非您指定不同的 getter,否则您不能声明名称以 new 开头的属性:

// Won't work:
property NSString *newTitle;

// Works:
property (getter=theNewTitle) NSString *newTitle;

我的属性名称是 newPath,这说明了...

【讨论】:

哇,惊人的发现!给我带来问题的日期属性是“newDueDate”。【参考方案2】:

如果您使用 ARC,则不应出现僵尸。你有一个变量声明为 unsafe_unretained 而不是弱?还是您在某处使用第三方库?内部使用手动引用计数代码的库可能是僵尸的来源。

unsafe_unretained 的不当使用可能会导致您引用已释放的对象,但是对于正常的强引用和弱引用,弱引用一释放就会被清零,因此一旦它们被释放,您应该无法向它们发送消息已被释放。

另一种可能性是滥用桥接演员表。那会搞砸ARC。你在使用桥接演员吗?

【讨论】:

项目中有 unsafe_unretained 属性(很大),但不与相关代码交互。 DataStoreController 不使用 ARC,但这从来都不是问题。 要明确项目使用核心数据和 mogenerator 声明一些 unsafe_unretained NSString 属性。 使用分配工具运行项目时,我发现 managedObject 的一个特定属性导致 ARC 在访问值时过度释放它。仍然不确定该属性是如何配置错误的,因为该类的其他日期属性之间没有区别。

以上是关于NSDate 内存管理使用 ARC Over Release的主要内容,如果未能解决你的问题,请参考以下文章

iOS之内存管理(ARC)

带有块、ARC 和非 ARC 的 Objective C 内存管理

iOS开发ARC内存管理技术要点

iOS开发ARC内存管理技术要点

iOS 5编程 内存管理 ARC技术概述

[OC学习笔记]自动引用计数初学