我已经在墙上撞了两天了,试图弄清楚我的代码到底是什么问题。到目前为止,没有。我发现的唯一事情就是一个对象试图自己调用release并且还没有实例化。 (虽然,出于某种原因,它不是100%的时间都会发生,只要它认为它是什么时候)
让我解释一下这个问题(也许我忽略了一些事情,我希望你们能为我的黑暗做些一些事情)
我的模型对象
Person {
NSString *name;
NSNumber *age;
}
@property(nonatomic, retain) NSNumber* TheAge;
@property(nonatomic, retain) NSString *TheName;
我的实施
@synthesize TheName = name;
@synthesize TheAge = age;
+(Person*)personFromDictionary:(NSDictionary*)dic {
Person* newPerson = [[[Person alloc] init]autorelease];
newPerson.theAge = [dic objectForKey:kAge];
newPerson.theName = [dic objectForKey:kName];
return newPerson;
}
-(void)dealloc {
self.TheAge = nil;
self.TheName = nil;
}
我有一个“收集器线程”,它从服务器读取JSON数组,下载并将其解析为字典。字典中的每个条目都对应一个人物对象 这个线程只是使用Person模型
是一个不同的类线程执行类似这样的操作(在自动释放池中)
NSDictionary *parsedDict = download.returnValue;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Person *tmpPerson = personFromDictionary
[entryDictionary setObject:tmpPerson forKey:kAge];
[pool release];
[self updateEntries:entryDictionary];
-(void)updateEntries:(NSMutableDictionary*)updatedDict {
NSArray *keys = [updatedDict allKeys];
for(NSString *key in allKeys){
Person *entry = [updatedDict valueForKey:key];
[entriesLock lock];
[currentPersonEntries setObject:entry forKey:key];
[entriesLock unlock];
}
}
当我遇到崩溃时(由于某种原因随机发生,我得到如下的堆栈跟踪
person dealloc
人setTheAge(bam崩溃)
我猜是因为setter看起来像这样
-(void)setTheAge:(NSString*)theAge {
[theAge retain];
[age release]; // it doesn't exist for some reason???
age = theAge;
}
我如何保护这种类型的东西?
答案 0 :(得分:2)
一些想法。
首先,你有:
Person {
NSString *name;
NSNumber *age;
}
@property(nonatomic, retain) NSNumber* TheAge;
@property(nonatomic, retain) NSString *TheName;
在您的实施中,您有:
@synthesize TheName = name;
@synthesize TheAge = age;
Apple不再建议你明确地定义你的ivars,但让你的综合语句来处理它(可能因为如果你拼错了其中一个,你最终会得到一个额外的,非预期的ivar)。所以你可能只想要:
@interface Person : NSObject
@property(nonatomic, retain) NSNumber* theAge;
@property(nonatomic, retain) NSString* theName;
@end
此外,在命名你的ivars时,新兴的标准是(当然,你可以做你想做的)使用下划线来表示ivars,并使用小写开始你的变量名...类的大写字母,变量的小写字母,例如:
@synthesize theName = _theName;
@synthesize theAge = _theAge;
其次,在你的dealloc
中,你将这些ivars设置为nil。虽然这是在ARC代码中发布的正确方法,但在非ARC代码中,您应该只使用您的ivars,并使用release命令:
- (void)dealloc {
[_theAge release];
[_theName release];
[super dealloc];
}
第三,你是在写那个setter setTheAge
还是在猜测编译器本身在做什么?您的代码可能会得到改进(您使用的是与您的属性相同的局部变量,这只是令人困惑,您想要进行键值通知等),但我不会解决这个问题,因为您除非你想要完成其他任务,否则最好让编译器自己设置setter。让我知道。
第四,你的-(Person*)personFromDictionary:(NSDictionary*)dic
是一种奇怪的方法。我建议编写自己的init,如:
- (Person*)initFromDictionary:(NSDictionary*) dic
{
self = [super init]; // I always inherit from NSObject, in which case you'd have this line
if (self)
{
self.theAge = [dic objectForKey:kAge];
self.theName = [dic objectForKey:kName];
}
return self;
}
这样,您可以创建Person对象,如:
Person *aPerson = [[Person alloc] initWithDictionary:entryDictionary];
您当前的实现假定Person
对象已经存在(因为您在方法名称前加上“ - ”而不是“+”),但随后会创建一个新对象。这有点奇怪。你可能会做类似的事情,但上面的代码模式更常见,并实现我想你想要的。
最后,我不确定你要对updateEntries
做什么,所以我不确定在那里建议什么,但我不太明白updateEntries
你的游泳池,无论你是说它是一个充满人物对象的字典等等。如果你描述你想要在那里完成的事情,我也很乐意给你两分钱。
<强>更新强>
顺便说一句,如果您正在调试代码,有时添加NSLog
语句会很有帮助。您可能希望为description
类创建Person
方法以便于此方法,以便您可以查看Person
对象的内容,例如:
- (NSString *)description
{
return [NSString stringWithFormat:@"Person (%p) {\n theName = '%@'\n theAge = %@\n}", self, self.theName, self.theAge];
}
这样,如果您有一个名为Person
的{{1}}对象,比如说aRandomPerson
,那么您可以使用以下语句:
NSLog(@"%@", aRandomPerson);
此外,如果您有一个包含Person
个对象的词典条目,如果您NSLog
该词典,您现在将拥有一个有意义的日志语句。这可以帮助您诊断NSDictionary
项中的内容(如果它确实包含Person
个对象,而不仅仅是NSString
和NSNumber
个对象。