0

我已经把头撞到墙上两天了,试图找出我的代码到底出了什么问题。到目前为止,什么都没有。我发现的唯一一件事是一个对象试图对其自身调用 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];

    }
}

当我遇到崩溃时(由于某种该死的原因随机发生,我得到堆栈跟踪如下

人释放

人 setTheAge (bam crash)

我猜是因为二传手看起来像这样

-(void)setTheAge:(NSString*)theAge {
  [theAge retain];
  [age release]; // it doesn't exist for some reason???
  age = theAge;
}

我该如何保护这种类型的东西?

4

1 回答 1

2

几个想法。

首先,你有:

Person {
    NSString *name;
    NSNumber *age;
}

@property(nonatomic, retain) NSNumber* TheAge;
@property(nonatomic, retain) NSString *TheName;

在您的实施中,您有:

@synthesize TheName = name;
@synthesize TheAge = age;

Apple 不再建议您明确定义您的 ivar,而是让您的 synthesize 语句处理它(可能是因为如果您拼错其中一个,您最终可能会得到一个额外的、意外的 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];
}

第三,您是在编写那个 settersetTheAge还是在猜测编译器自己在做什么?您的代码可能可以改进(您使用的局部变量与您的属性相同,这只是令人困惑,您想要进行键值通知等),但我不会解决这个问题,因为您最好让编译器执行自己的设置器,除非您要完成其他工作。让我知道。

第四,你-(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你的池子,无论你的意思是它是一本充满Person 对象等。如果您描述您要在那里完成的工作,我也很乐意为此给您两分钱。

更新:

顺便说一句,如果您正在调试代码,有时添加NSLog语句会很有帮助。不过,您可能希望description为您的类创建一个方法Person来促进这一点,以便您可以查看Person对象的内容,例如:

- (NSString *)description
{
    return [NSString stringWithFormat:@"Person (%p) {\n  theName = '%@'\n  theAge = %@\n}", self, self.theName, self.theAge];
}

这样,如果您有一个Person名为 的对象,aRandomPerson则可以使用如下语句:

NSLog(@"%@", aRandomPerson);

此外,如果你有一个包含Person对象的字典条目,如果你NSLog是那个字典,你现在将有一个有意义的日志语句。这可以帮助您诊断项目中的内容NSDictionary(如果它真的有Person对象而不仅仅是NSStringNSNumber对象)。

于 2012-06-25T19:20:57.077 回答