2012-06-25 5 views
0

Я уже два дня ударяю головой о стену, пытаясь понять, что черт не так с моим кодом. Пока ничего. Единственное, что я обнаружил, это тот факт, что объект пытается вызвать релиз сам по себе, и он еще не был создан. (хотя по какой-то причине это не происходит в 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

нить делает что-то вроде этого (в качестве autorelease бассейна)

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]; 

    } 
} 

Когда я получаю аварию (что происходит случайным образом по какой-то чертовой причине, я получаю трассировку стека следующим образом

людей dealloc

людей setTheAge (бАМ аварии)

Я предполагаю, потому что сеттер будет выглядеть примерно так

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

Как я могу защитить против такого рода вещи?

+0

Вы пытались удалить autorelease в Person * newPerson = [[[Person alloc] init] autorelease]; – Dhawal

+0

Кстати, я не пробовал это на примере кода выше, но я бы сказал, что статический анализатор (shift-command-B), вероятно, создаст всевозможные предупреждения о вышеуказанном коде. Если вы просто попадаете в Objective C, предупреждения, сообщаемые статическим анализатором, могут быть очень полезными. Вы должны иметь _zero_ предупреждения от анализатора. Я думаю, что мой ответ ниже - более конструктивный ответ (вместо того, чтобы пробираться сквозь кучу предупреждений), но я просто хотел предложить вам проверить этот замечательный маленький инструмент. – Rob

ответ

2

Несколько мыслей.

Во-первых, у вас есть:

Person { 
    NSString *name; 
    NSNumber *age; 
} 

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

И в вашей реализации, у вас есть:

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

Apple, больше не рекомендует определять Ивар в явном виде, но пусть ваше синтезируют заявление заботиться о нем (вероятно, потому, что если вы ошибаетесь в одном из них, вы можете получить дополнительный, непреднамеренный ivar). Таким образом, вы можете просто хотите:

@interface Person : NSObject 

@property(nonatomic, retain) NSNumber* theAge; 
@property(nonatomic, retain) NSString* theName; 

@end 

Кроме того, при именовании Ивара, формирующийся стандарт (но, конечно, вы можете делать то, что вы хотите), чтобы использовать подчеркивание для Ивар, и начиная ваши имена переменных в нижнем регистре ... верхний регистр для классов, в нижнем регистре для переменных, например:

@synthesize theName = _theName; 
@synthesize theAge = _theAge; 

во-вторых, в ваших dealloc вы устанавливаете эти Ивар к нулю. Несмотря на то, что это правильный путь, чтобы освободить в ARC кода, в не-ARC кода, вы должны просто использовать свои Ивар, и использовать команду выпуска:

- (void)dealloc { 
    [_theAge release]; 
    [_theName release]; 

    [super dealloc]; 
} 

В-третьих, вы пишете, что сеттер setTheAge или вы догадываясь, что компилятор делает сам?Вероятно, ваш код может быть улучшен (вы используете локальную переменную, которая совпадает с вашим свойством, что просто запутывает, вы хотите делать уведомления о значении ключа и т. Д.), Но я не буду обращаться к этому, потому что вы «Лучше бы просто позволить компилятору сделать свой собственный сеттер, если только не будет чего-то еще, что вы пытаетесь выполнить. Дай мне знать.

В-четвертых, ваш -(Person*)personFromDictionary:(NSDictionary*)dic - любопытный метод. Я предлагаю писать свой собственный первонач, как:

- (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 и т. д. Если вы опишете, что вы пытаетесь сделать там, я был бы рад дать вам мои два цента на это.

Update:

Кстати, если вы отладки кода, иногда добавляя 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 объектов, а не только NSString и NSNumber объектов).

+0

Отличный подробный ответ, я на самом деле сделал опечатку в своем человекеFromDictionary, это на самом деле метод класса. Но теперь мне интересно, что произойдет, если этот метод вызывается несколько раз? Это повлияет на поведение? – MrShoot

+0

@MrShoot Нет, если это метод класса, то это, вероятно, работает. Но ваш фрагмент, вызывающий 'updateEntries', в лучшем случае трудно следовать, и, возможно, немного подозрительный. Возможно, в попытке изолировать нас от нерелевантных деталей вы опустили какой-то код, который поместил бы это в контекст. Как изменяется набор 'personFromDictionary' (btw, используя одно и то же имя для метода и переменной)?Кроме того, в entryDictionary вы устанавливаете ключ kAge для Person (но в методе 'personFromDictionary' вы предлагаете, чтобы этот ключ был NSNumber). ... – Rob

+0

@MrShoot В методе 'updateEntries' вы также передаете' updatedDict', а затем вы говорите, что у каждого ключа есть Person. Это _really_ словарь, для которого каждый ключ содержит объект Person? Это всего лишь несколько случайных вопросов, но код 'updateEntries' выглядит просто странно. Кроме того, похоже, что вы создаете пул, но у вас есть код до и после этого пула. Есть ли причина, почему это не все в пуле? Возможно, если вы предоставите немного более полный фрагмент этого кода, возможно, мы сможем понять это, но я не могу сделать головы или хвосты того, что вы пытаетесь сделать. – Rob