【问题标题】:Should we release NSDate manually?我们应该手动释放 NSDate 吗?
【发布时间】:2011-05-19 05:16:45
【问题描述】:

我在头文件中使用以下配置声明了 NSDate:

# TestController.h
@interface TestController : UITableViewController{
    NSDate      *selectedDate;
    NSManagedObject *task;
}
    @property (nonatomic, retain) NSManagedObject *managedObject;
    @property (retain) NSDate *selectedDate 
@end

# TestController.m
@implementation TestController
    - (void)viewDidLoad {
        self.selectedDate = [managedObject valueForKey:@"title"];
    }
    - (void)viewDidUnload {
        self.task = nil;
        self.selectedDate = nil;
    }

    - (void)dealloc {
        [self.task release]
      [self.selectedDate release];
      [super dealloc];
    }
@end

根据我的理解,您应该释放分配、复制或保留的变量。由于我在这里保留了变量数据,所以我在dealloc时释放。但是,最终抛出内存释放错误:

"[NSDate isNSDate]: 消息发送到已释放实例 0x6923750"

如果我没有手动释放它,它工作正常。我的问题是我应该为这种情况释放变量吗?

更新:

使用僵尸模板进行了仪器测试,这是输出:

#   Category    Event Type  RefCt   Timestamp   Address Size    Responsible Library Responsible Caller
0   __NSDate    Malloc  1   1331055104  0x895e9d0   16  CoreData    -[NSSQLCore _prepareResultsFromResultSet:usingFetchPlan:withMatchingRows:]
1   __NSDate    Retain  2   1333056000  0x895e9d0   0   Task    -[TaskViewCell configureData:]
2   __NSDate    Retain  3   3045008128  0x895e9d0   0   CoreData    -[NSManagedObject(_NSInternalMethods) _newPropertiesForRetainedTypes:andCopiedTypes:preserveFaults:]
3   __NSDate    Retain  4   3054921984  0x895e9d0   0   CoreData    -[NSSQLRow copy]
4   __NSDate    Release 3   3059244032  0x895e9d0   0   CoreData    -[NSSQLOperation dealloc]
5   __NSDate    Release 2   3059607040  0x895e9d0   0   CoreData    -[NSKnownKeysDictionary1 dealloc]
6   __NSDate    Retain  3   3715918848  0x895e9d0   0   CoreData    -[NSManagedObject(_NSInternalMethods) _newPropertiesForRetainedTypes:andCopiedTypes:preserveFaults:]
7   __NSDate    Retain  4   3727657984  0x895e9d0   0   CoreData    -[NSSQLRow copy]
8   __NSDate    Release 3   3730131200  0x895e9d0   0   CoreData    -[NSSQLOperation dealloc]
9   __NSDate    Release 2   3730286080  0x895e9d0   0   CoreData    -[NSKnownKeysDictionary1 dealloc]
10  __NSDate    Retain  3   4250617856  0x895e9d0   0   CoreData    -[NSManagedObject(_NSInternalMethods) _newPropertiesForRetainedTypes:andCopiedTypes:preserveFaults:]
11  __NSDate    Retain  4   4250759936  0x895e9d0   0   CoreData    -[NSManagedObject setValue:forKey:]
12  __NSDate    Release 3   4250761984  0x895e9d0   0   CoreData    -[NSManagedObject setValue:forKey:]
13  __NSDate    Retain  4   4260489984  0x895e9d0   0   CoreData    -[NSSQLRow copy]
14  __NSDate    Release 3   4263536896  0x895e9d0   0   CoreData    -[NSSQLOperation dealloc]
15  __NSDate    Release 2   4263687168  0x895e9d0   0   CoreData    -[NSKnownKeysDictionary1 dealloc]
16  __NSDate    Release 1   4656624128  0x895e9d0   0   Task    -[TaskEditController dealloc]
17  __NSDate    Retain  2   7570179840  0x895e9d0   0   CoreData    -[NSManagedObject(_NSInternalMethods) _newPropertiesForRetainedTypes:andCopiedTypes:preserveFaults:]
18  __NSDate    Retain  3   7570360064  0x895e9d0   0   CoreData    -[NSManagedObject setValue:forKey:]
19  __NSDate    Release 2   7570361088  0x895e9d0   0   CoreData    -[NSManagedObject setValue:forKey:]
20  __NSDate    Retain  3   7577499136  0x895e9d0   0   CoreData    -[NSSQLRow copy]
21  __NSDate    Release 2   7602608128  0x895e9d0   0   CoreData    -[NSSQLOperation dealloc]
22  __NSDate    Release 1   7602752256  0x895e9d0   0   CoreData    -[NSKnownKeysDictionary1 dealloc]
23  __NSDate    Release 0   7971558144  0x895e9d0   0   Task    -[TaskEditController dealloc]
24  __NSDate    Zombie  -1  9697122048  0x895e9d0   0   Foundation  -[NSDateFormatter stringForObjectValue:]

真的不明白这是什么意思。但是,我的猜测是 coredata 发布 NSDate 即使保留?

【问题讨论】:

    标签: iphone ios objective-c


    【解决方案1】:

    解决过度释放对象问题的最佳方法是启动 Instruments(在 XCode 中,输入 ⌘-I 而不是 ⌘-R)并选择“Zombies”模板——它会告诉你在哪里每个对象都被保留和释放,并在您的代码向已发布的实例发送消息时告诉您。

    在这种情况下,不平衡的版本可能潜伏在您的代码中的其他地方,并且在您的 dealloc 方法中放置一个版本会暴露其他地方的问题。无论如何,对您问题的直接回答是“是的,您应该释放您保留的变量”,并且您在此处发布的代码具有正确的保留与发布比率(即一对一),所以我会寻找您可能会发布此 NSDate 的其他地方。

    【讨论】:

    • 好吧,快速搜索一下项目,并没有找到任何发布日期对象的地方。我从 ManageObject 获取日期对象,我也发布了它。这会导致问题吗?我更新了我的代码,很快就会尝试你的方法。谢谢
    【解决方案2】:

    调用[ self.selectedDate release ] 将减少self.selectedDate 中对象的保留计数,但是self.selectedDate 仍然包含对(现在已过度发布的)日期对象的引用。

    你应该这样做:

    self.selectedDate = nil.

    因为:

    self.selectedDate = nil

    是这个实际代码的方便语法:

    [ self setSelectedDate:nil ]

    方法setSelectedDate:自动生成

    @synthesize selectedDate.

    由于属性声明为retain,生成的setter如下所示:

    -(void)setSelectedDate:(NSDate*)date
    {
        [ selectedDate release ] ; // refers to the generated selectedDate instance variable in this class
        selectedDate = [ date retain ] ;
    }
    

    最后,如果您不需要原子访问(大多数情况下不需要),请改用 nonatomic 声明:

    @property ( nonatomic, retain ) NSDate * date
    

    【讨论】:

    • 感谢您的详细解释。我更新了我的问题以更好地说明我的代码。我确实将我的日期对象设置为 nil 以清除参考。我也尝试过你的非原子声明,但到目前为止还没有运气。
    • btw--viewDidUnload 并不总是被调用。只有在卸载视图时内存不足的情况下才会调用它。反正dealloc里面的代码还是要改成self.selectedDate = nil
    • 在这种情况下,我会按照 Scott Forbes 的建议尝试 Instruments。 (使用分配工具——您将能够看到程序中每个 NSDate 的整个保留/释放/自动释放/分配历史记录。问题应该会立即跳出来。
    • 试过了。我已经用日志更新了帖子,听起来像 coredata 发布 NSDate。
    • (除非你 100% 确定,否则我不会怀疑 Core Data。)看起来[ TestController dealloc ] 正在执行两次。那不应该发生。您正在过度释放 TestController,但在此之前可能会导致麻烦,您遇到了这个问题。检查您的 TestController 保留/释放
    【解决方案3】:

    是的,您应该释放您拥有的任何变量(分配、复制或保留)。但是,在 dealloc 方法中释放 NSDate 变量的正确方法应该是:

    [selectedDate release];
    selectedDate = nil;
    

    self.selectedDate = nil;
    

    第二种方法将调用属性的选择器方法,该方法首先释放变量,然后将 nil 分配给处理程序。因此,这一行代码将释放它并将其设置为 nil,就像第一个选项中的两个单独的行一样。

    【讨论】:

    • 将指针设置为 nil 不会释放它,引用仍然存在。
    • 此评论是关于第一种还是第二种方法?
    • 好的,我对带有保留的属性的理解是;通过将 self 与属性一起使用将调用其 setter 方法并首先释放旧值,不是吗?它不是这样工作的吗?- (void) setVarid) newValue { if (var != newValue) { [var release];变量 = 新值; [新值保留]; } } ?
    • 点赞。使用self.selectedDate = nil 是正确的。这相当于 [ self setSelectedDate:nil ]。生成的设置器 (setSelectedDate:) 将在设置时释放现有对象,因为该属性被声明为 retain
    • @Imran 对不起,你说得对,默认设置器会释放旧内存,我误解了你写的内容。我已经删除了我的反对票。
    【解决方案4】:

    试试

    [selectedDate release];
    

    代替

    [self.selectedDate release];
    

    【讨论】:

    • 没有。变量引起的错误之前已经发布过,但是我只在类dealloc方法上发布过。
    猜你喜欢
    • 1970-01-01
    • 2019-08-20
    • 2011-03-21
    • 2017-04-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-31
    • 1970-01-01
    • 2011-10-12
    相关资源
    最近更新 更多