【问题标题】:arrayWithContentsOfFile: results in crasharrayWithContentsOfFile:导致崩溃
【发布时间】:2011-04-23 07:34:40
【问题描述】:

我正在创建一个应用程序,但遇到 EXC_BAD_ACCESS 错误。


代码

@interface DNProjectsCategory : DNCategory {
  NSArray *projects;
}

@property(nonatomic, retain) NSArray *projects;

@end

还有:

@implementation DNProjectsCategory
@synthesize projects;

// MEM

- (void)dealloc {
  [projects release];
  
  [super dealloc];
}

// INIT.
- (id)init {
  if (self = [super init]) {
    title = NSLocalizedString(@"PROJECTS", nil);
    isSubCategory = NO;
    
    // Initialize projects
    //!!LINE 32 IS HERE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    projects = [NSArray arrayWithContentsOfFile:DNPROJECTSFILE];
  }
  
  return self;
}

// CATEGORIES

- (NSArray *)subCategories {
  NSMutableArray *projectsArray = [[[NSMutableArray alloc] init] autorelease];
  
  for (NSDictionary *project in projects) {
    DNCategory *projectCategory = [[DNCategory alloc] initWithTitle:[project valueForKey:@"title"]
                                                      subCategories:nil
                                                      isSubCategory:YES];
    
    [projectsArray addObject:projectCategory];
    [projectCategory release];
  }
  
  return projectsArray;
}

DNPROJECTSFILE 的内容

http://gist.github.com/618628


控制台和仪器

这是控制台在运行时显示的内容(已启用 NSZombie):

run
[Switching to process 41257]
Running…
2010-10-09 23:32:36.899 Done[41257:a0f] *** -[CFString isKindOfClass:]: message sent to deallocated instance 0x1001caab0
sharedlibrary apply-load-rules all

这是 Instruments 在 NSZombie 测试中所说的:

僵尸消息

Objective-C 消息已发送到地址为 0x10012af80 的已释放对象(僵尸)。

 

堆栈跟踪

   0 CoreFoundation _CFRuntimeCreateInstance
   1 CoreFoundation __CFStringCreateImmutableFunnel3
   2 CoreFoundation CFStringCreateWithBytes
   3 CoreFoundation _uniqueStringForCharacters
   4 CoreFoundation getString
   5 CoreFoundation parseXMLElement
   6 CoreFoundation parseXMLElement
   7 CoreFoundation parseArrayTag
   8 CoreFoundation parseXMLElement
   9 CoreFoundation parsePListTag
  10 CoreFoundation parseXMLElement
  11 CoreFoundation _CFPropertyListCreateFromXMLStringError
  12 CoreFoundation _CFPropertyListCreateWithData
  13 CoreFoundation CFPropertyListCreateFromXMLData
  14 Foundation _NSParseObjectFromASCIIPropertyListOrSerialization
  15 Foundation +[NSArray(NSArray) newWithContentsOf:immutable:]
  16 Foundation +[NSArray(NSArray) arrayWithContentsOfFile:]
  17 Done -[DNProjectsCategory init] /Users/rsonic/Developer/Done/DNProjectsCategory.m:32
  18 Done -[DNBindingsController categories] /Users/rsonic/Developer/Done/DNBindingsController.m:18
  19 Foundation -[NSObject(NSKeyValueCoding) valueForKey:]
  20 Foundation -[NSObject(NSKeyValueCoding) valueForKeyPath:]
  21 AppKit -[NSBinder valueForBinding:resolveMarkersToPlaceholders:]
  22 AppKit -[NSArrayDetailBinder _refreshDetailContentInBackground:]
  23 AppKit -[NSObject(NSKeyValueBindingCreation) bind:toObject:withKeyPath:options:]
  24 AppKit -[NSIBObjectData nibInstantiateWithOwner:topLevelObjects:]
  25 AppKit loadNib
  26 AppKit +[NSBundle(NSNibLoading) _loadNibFile:nameTable:withZone:ownerBundle:]
  27 AppKit +[NSBundle(NSNibLoading) loadNibNamed:owner:]
  28 AppKit NSApplicationMain
  29 Done main /Users/rsonic/Developer/Done/main.m:13
  30 Done start

问题

我真的不知道如何修复这个双重版本。据我所知,除了dealloc 之外,我不会在任何地方发布projects 变量。有人可以帮我吗?谢谢。

【问题讨论】:

  • #define DNPROJECTSFILE [[NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:@"/RSONIC Done/projects.xml"]
  • @Andrew 一个由 NSDitrionaries 组成的 NSArray。

标签: objective-c cocoa memory nszombie


【解决方案1】:

您没有使用访问器,因此永远不会保留项目。 您的 init 方法有两种选择:

projects = [[NSArray arrayWithContentsOfFile:DNPROJECTSFILE] retain];

self.projects = [NSArray arrayWithContentsOfFile:DNPROJECTSFILE];

@property(nonatomic, retain) NSArray *projects;

该属性“创建”两个方法,一个 getter - (NSArray *)projects 和一个,在您的情况下更重要的是 setter - (void)setProjects:(NSArray*)a; 您在属性声明中编写的保留语句仅适用于 setter。如果直接使用projects = foo; 设置变量,则不使用setter。
但是self.projects = foo; 等价于[self setProject:foo],这是您动态创建的setter。
您的二传手看起来与此类似:

- (void)setProjects:(NSArray*)anArray {
    [anArray retain];
    [projects release];
    projects = anArray;
}

因此,如果您使用 setter,您从 arrayWithContentsOfFile: 获得的自动释放的 NSArray 将被保留。
您在 Objective C 中所做的每个调用不是“alloc”、“copy”、“retain”或任何以 new 开头的调用都会返回一个自动释放的对象。如果您想稍后使用它们(即在您离开创建它们的方法之后),您必须保留它们。

也许你想再看看Apple Memory Managment Guide

【讨论】:

  • 它有效,但我不太明白如何。请你解释一下好吗?我从来不明白retain 是如何工作的。 ^^
  • @Koning:[NSArray array...] 方法返回一个自动自动释放的实例。因此,在初始化器离开后的某个时间,实例由自动释放池释放。为了防止这种情况,您需要保留该实例以表明您想要/需要保留该实例。您可以通过手动调用 retain 或将其分配给为您进行保留的属性(因为它具有保留标志)来实现。
  • @koning-baard 我解释了您在我的编辑中遇到的保留释放问题的另一面。 HTH。
猜你喜欢
  • 2018-01-23
  • 2020-12-02
  • 2013-11-11
  • 2011-01-24
  • 2015-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多