【问题标题】:NSArray acts weirdly with objects going out of scopeNSArray 在对象超出范围时行为怪异
【发布时间】:2011-01-31 22:22:17
【问题描述】:

NSArray 有一个奇怪的问题,我的数组中的一些对象成员超出了范围,但其他成员没有:

我有一个名为 Section 的简单对象。 它有3个成员。

@interface Section : NSObject {
    NSNumber *section_Id;   
    NSNumber *routeId;
    NSString *startLocationName;
}
@property(nonatomic,retain)  NSNumber *section_Id;  
@property(nonatomic,retain)  NSNumber *routeId;
@property(nonatomic,retain)  NSString *startLocationName;
@end


@implementation Section

@synthesize section_Id; 
@synthesize routeId;
@synthesize startLocationName;

//Some static finder methods to get list of Sections from the db
+ (NSMutableArray *) findAllSections:{


- (void)dealloc {
    [section_Id release];
    [routeId release];
    [startLocationName release];

    [super dealloc];
}

@end

我从数据库中用一个名为findAllSection的方法填充它

self.sections = [Section findAllSections];

在查找所有部分中,我创建了一些局部变量,用 db 中的数据填充它们。

NSNumber *secId = [NSNumber numberWithInt:id_section];
NSNumber *rteId = [NSNumber numberWithInt:id_route];
NSString *startName = @"";

然后新建一个Section,并将这些局部变量的数据存储在Section中

Section *section = [[Section alloc] init];

section.section_Id = secId;
section.routeId = rteId;
section.startLocationName = startName;

然后我将部分添加到数组中

[sectionsArray addObject:section];

然后我清理,释放局部变量和我添加到数组中的部分 [secId 发布]; [rteId 发布]; [开始名称发布]; [locEnd_name 释放];

[section release];

在所有部分的循环中重复(释放局部变量,部分在每个循环中完成)

方法返回,我检查了数组,所有的部分都在那里。我似乎无法进一步挖掘以查看数组中 Section 对象的值(这可能吗)

稍后我尝试检索其中一个部分

我从数组中得到它

Section  * section = [self.sections objectAtIndex:row];

然后检查值

NSLog(@" SECTION SELECTED:%@",section.section_Id);

但是对section.section_Id 的调用由于section.section_Id 超出范围而崩溃。

我检查了这个 Section 对象的其他成员,他们都没事。 经过一些试验和错误,我发现通过注释掉成员变量的释放对象就可以了。

//[secId release];
[rteId release];
[startName release];
[locEnd_name release];


[section release];

我的问题是:

我打扫得好吗?

我应该释放添加到数组中的对象和函数中的局部变量吗?

我的 dealloc 在 Section 中可以吗?

这段代码看起来没问题,我应该在别处寻找问题吗?

我没有做任何复杂的事情,只是从数据库中填充数组,在表格单元中使用它。

我可以注释掉这个版本,但更想知道为什么它会起作用,以及我是否不应该这样做。唯一释放secId 的地方是dealloc。

【问题讨论】:

    标签: objective-c memory-management nsarray


    【解决方案1】:

    您不应发布secIdrteIdstartNamesecIdrteId 是指向 NSNumber 实例的指针,该实例使用返回已自动释放对象的工厂方法创建。不需要释放静态字符串(即@"")。您需要重新阅读Memory Management Programming Guide。然后再读一遍;-) 这将是你的朋友。

    【讨论】:

    • @Barry 也打败了我。不过,他是对的。除了少数例外,您只释放从initcopynew 方法创建的对象。
    • 我建议您对 SO 上的任何人告诉您有关内存管理的任何内容都轻描淡写。去由巴里的内存管理规则联系起来。人们倾向于非正式地重述它们,并且经常说错了。例如,kubi 只是省略了copymutableCopy。所以不要过分依赖重述规则。
    • Barry 说得对,但澄清一下,您不应该发布您正在创建的 local NSNumber 实例。您仍然应该释放实例变量。通常,您可以通过将 nil 分配给属性 (self.section_Id = nil;) 而不是在实例变量上调用 release 来更时尚地做到这一点。
    • @warrenm,请nil 分配给属性以释放析构函数中的实例变量。如果您曾经向属性设置器添加副作用,那么这样做会很痛苦。标准做法是在 initdealloc 方法中使用原始实例变量,并在其他任何地方访问属性。
    • 我非常不同意,除非您使用的是 KVO。在所有其他情况下,尤其是如果您正在向 mutator 添加自定义行为,您应该仔细检查您如何执行最终发布,在这种情况下您可以根据需要进行更改。否则,没有理由从风格上贬低这种选择。
    【解决方案2】:

    我将第二(第三)建议阅读内存管理规则。

    TL;DR 版本是您alloc 并调用方法名称中带有init 的任何方法,由您负责发布。例如:

    NSString *string = [[NSString alloc] initWithFormat:@"%@", someObject];
    

    在这种情况下,您必须释放 string。然而:

    NSString *string = [NSString stringWithFormat:@"%@", someObject];
    

    这里string 是自动释放的。基本上相当于这样:

    NSString *string = [[[NSString alloc] initWithFormat@"%@", someObject] autorelease];
    

    ...意味着下一次通过事件循环(这意味着可能在您的函数返回时),系统将为您发送release消息给它。 Apple 将这些称为“便利方法”。

    如果你有这样的事情:

    NSString *string = @"foo";
    

    然后string 指向 NSString 的一个实例,该实例由运行时在您的程序初始化时创建,并且在您的程序终止之前不会超出范围。也不要release 这些。

    再次阅读指南并将其添加为书签。但这应该回答您的直接问题。

    【讨论】:

    • 大家干杯。 //TODO:星期五 - R.T.F.M. (阅读 Feckin 手册)或者应该是 R.T.F.MMM(阅读 Feckin 内存管理手册);)
    【解决方案3】:

    您正在释放不属于您的对象。你应该阅读memory management rules

    【讨论】:

      猜你喜欢
      • 2011-11-23
      • 1970-01-01
      • 1970-01-01
      • 2014-03-15
      • 1970-01-01
      • 1970-01-01
      • 2011-07-10
      • 1970-01-01
      • 2012-04-22
      相关资源
      最近更新 更多