arrayWithContentsOfFile: приводит к падению

Я создаю приложение и получаю ошибку 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;
}

СОДЕРЖАНИЕ ДНЕПРОЕКТА

Смотрите 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:

Zombie Messaged

Сообщение 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

ВОПРОС

Я действительно не знаю, как исправить этот двойной релиз. Насколько я знаю, я не выпускаю projects переменная в любом месте, кроме dealloc, Может кто-нибудь помочь мне, пожалуйста? Благодарю.

1 ответ

Решение

Вы не используете аксессор, поэтому проекты никогда не сохраняются. Два варианта для вашего метода инициализации:

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

или же

self.projects = [NSArray arrayWithContentsOfFile:DNPROJECTSFILE];

@property(nonatomic, retain) NSArray *projects;

свойство "создает" два метода, геттер - (NSArray *)projects и, в вашем случае более важно, сеттер - (void)setProjects:(NSArray*)a; Заявление о сохранении, которое вы написали в декларации свойства, относится только к установщику. Если вы установите переменную непосредственно с projects = foo; сеттер не используется.
Но self.projects = foo; эквивалентно [self setProject:foo], который является вашим динамически созданным сеттером.
Ваш сеттер выглядит примерно так:

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

Поэтому, если вы используете сеттер, ваш автоматически выпущенный NSArray, полученный из arrayWithContentsOfFile: сохраняется.
Каждый вызов, который вы делаете в Objective C, который не является "alloc", "copy", "retain" или чем-либо, начинающимся с new, возвращает автоматически высвобождаемый объект. Вы должны сохранить их, если хотите использовать их позже (т.е. после того, как вы оставили метод, в котором они были созданы).

Может быть, вы хотите еще раз взглянуть на Руководство по управлению памятью Apple

Другие вопросы по тегам