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