2010-11-14 4 views
0

J'ai dansé avec un tambourin pendant un moment, mais je ne sais toujours pas quelle est la raison de cette erreur. J'ai une tableView avec l'historique des requêtes des utilisateurs de sqlite base. Je suis nouveau sur iPhone en développement, donc mon code peut être un peu excessif. La hiérarchie est la suivante:table déroulante: message envoyé à l'instance désaffectée

  • HistoryModel modèle-objet avec certains procédés d'initialisation

  • HistoryDataController obtient des données à partir de la base de données et présente un tableau d'objets HistoryModel

  • HistoryViewController sous-classe de UITableView, affiche les données

  • AppDelegate il i stocker d'abord un tableau d'objets HistoryModel (en l'obtenant HistoryDataController) pour HistoryViewController pour y accéder.

Le problème est, quand je défiler la table ou ouvrir l'onglet avec elle pour la deuxième fois - il se bloque avec - [CFString retain]: message envoyé à l'instance désallouées

code :

HistoryModel.h classe assez inutile pour ce cas, mais je veux que travaillé à répéter dans plusieurs cas identiques, mais un peu plus compliqué

@interface HistoryModel : NSObject { 
    int entry_id; 
    NSString *word; 
} 

- (id)initWithWord:(NSString *)word; 
- (id)initWithWord:(NSString *)word andId:(int)entry_id; 

@property int entry_id; 
@property (retain) NSString *word; 

@end 

HistoryModel.m

@implementation HistoryModel 

@synthesize entry_id, word; 

- (id)initWithWord:(NSString *)_word { 
    [super init]; 
    word = _word; 
    return self; 
} 

- (id)initWithWord:(NSString *)_word andId:(int)_entry_id { 
    entry_id = _entry_id; 
    return [self initWithWord:_word]; 

@end 

HistoryDataController.h i utilise l'entité de cette classe en tant que getter de données et une mémoire pour les objets HistoryModel (en propriété historyEntries)

@interface HistoryDataController : NSObject { 
    NSMutableArray *historyEntries; 
    int limit; 
} 

@property (nonatomic, retain) NSMutableArray *historyEntries; 
@property int limit; 

- (id)initWithHistoryData; 
- (id)initWithHistoryDataLimitedBy:(int)limit; 

HistoryDataController.m

@implementation HistoryDataController 
@synthesize historyEntries, limit; 

- (id)initWithHistoryDataLimitedBy:(int)_limit { 
    [super init]; 

    // Getting data from database 
    {some DB stuff} 

    NSMutableArray *tmp_historyEntries = [[NSMutableArray alloc] init]; 
    while(result == SQLITE_ROW) 
    { 
     HistoryModel *currentHistoryEntry = [[HistoryModel alloc] initWithWord:[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 1)] ]; 
     [tmp_historyEntries addObject:currentHistoryEntry]; 
     result = sqlite3_step(statement); 
    } 
    historyEntries = tmp_historyEntries; 

    {some DB stuff} 
    return self; 
} 
@end 

HistoryViewController.h sous-classe de UITableViewController, obtient des données stockées dans la propriété de AppDelegate et affiche dans le tableau

@interface HistoryViewController : UITableViewController { 
    IBOutlet UITableView *historyTable; 
    SynonymsAppDelegate *appDelegate; 
} 

@property (retain) UITableView *historyTable; 

@end 

HistoryViewController.m

@implementation HistoryViewController 
@synthesize historyTable, historyEntriesToShow; 

- (void)viewWillAppear:(BOOL)animated { 
    [super viewWillAppear:animated]; 

    appDelegate = (SynonymsAppDelegate *)[[UIApplication sharedApplication] delegate]; 
    [appDelegate initHistoryList]; 
    [self.tableView reloadData]; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 

    {standart cell stuff} 

    HistoryModel *historyEntry = [appDelegate.historyList objectAtIndex:indexPath.row]; 
    cell.textLabel.text = historyEntry.word; 
    return cell; 
} 

@end 

SynonymsAppDelegate.h lorsque onglet Historique ouvre, il obtient des données de la propriété HistoryList, qui a été formé par HistoryDataController :)

@interface SynonymsAppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate> { 
    ... 
    NSMutableArray *historyList; 
} 
... 
@property (retain) NSMutableArray *historyList; 

- (void)initHistoryList; 

@end 

SynonymsAppDelegate.m

@implementation SynonymsAppDelegate 
@synthesize window, tabBarController, historyList; 

- (void)initHistoryList { 
    HistoryDataController *historyDataController = [[HistoryDataController alloc] initWithHistoryData]; 
    historyList = historyDataController.historyEntries; 
} 

@end 

Fuf. Désolé pour tant de code, mais je crois que tout est nécessaire. En raison de la moitié de la journée passée sur cette question, je devine, ce problème est en quelque sorte lié à l'entité HistoryModel, car lorsque je supprime "conserver" pour mot @property, l'erreur bascule pour - [CFString isEqualToString: ]: message envoyé à l'instance désallouées

Je ne suis pas vraiment expérimenté dans la gestion de la mémoire, mais je suppose que ce HistoryModel objets à l'intérieur historyEntry dans HistoryViewController ou HistoryList dans AppDelegatesort en même temps lorsque vous faites défiler le tableau ou ouvrez l'onglet pour la deuxième fois. Mais c'est juste ma deviner. Vraiment apprécier l'aide.

+0

Des pièces assez longues et pourtant importantes manquent. Pour les propriétés NSString, vous voulez presque toujours (copier) au lieu de conserver. Plus de code pour votre HistoryModel pourrait être utile. Probablement le code est ailleurs, cependant - peut-être une libération à un NSString autoreleased. – Eiko

+0

Ne sait pas si c'est le problème, mais je pense que vous avez besoin d'un retenir dans votre appDelegate: historyList = [historyDataController.historyEntries conserver]; – Rengers

+0

Merci, j'ai essayé tout ce que vous avez proposé, mais cela n'a pas résolu le problème. Pour Eiko: c'est tout le code de HistoryModel que j'ai, sauf pour les méthodes init, qui, comme je l'ai mentionné, ne sont pas utilisées de toute façon. Rengers, j'ai essayé ta solution, ça n'a pas aidé mais j'essaierai de retenir d'autres objets. En fait, je n'ai pas encore fait de gestion de la mémoire, parce que je n'ai pas d'expérience et c'est juste le début du programme. – nikans

Répondre

1

Vous avez définitivement un problème dans votre - [HistoryModel initWithWord] Vous devriez conserver (ou mieux encore copier) la chaîne qui est passée.

je l'écrire comme ceci:

- (id)initWithWord:(NSString *)_word { 
    [super init]; 
    self.word = _word; // this is same as [self setWord:_word] 
    return self; 
} 

Il y a des gens qui diraient à l'aide du compositeur dans votre init est pas une bonne pratique. Je ne suis pas de ce camp. Mais dans tous les cas, vous devez conserver ou copier cette chaîne.

Ensuite, vous rencontrez un problème similaire dans votre délégué d'application, où vous avez des fuites sur chaque HistoryDataController lorsque vous en créez un nouveau. (et cela arrive chaque fois que cette vue de table apparaît). Et vous devriez vraiment conserver ce tableau aussi (bien que cela n'ait pas encore causé de problème parce que vous fuyez les HistoryDataControllers et masquez donc ce problème jusqu'à présent.)

Mon conseil général à vous serait de ne pas remettre la gestion de la mémoire. Revenir plus tard et essayer de faire les choses correctement est compliqué et sujet aux erreurs, même pour un développeur expérimenté. Il est beaucoup, beaucoup plus facile de construire les bonnes techniques de gestion de la mémoire dans le code que vous écrivez. Cela signifie qu'il vaut la peine de lire le guide de gestion de la mémoire avant de commencer à coder quelque chose comme ça. Vous économiserez beaucoup de temps et de frustration.

+0

Merci beaucoup. Maintenant, quand cela fonctionne relativement stable, je vais lire quelques informations sur la gestion de la mémoire et essayer de résoudre ces problèmes. Mais puis-je demander, qu'est-ce que cela signifie "vous avez un problème similaire dans votre délégué de l'application où vous fuyez chaque HistoryDataController que vous en créez un nouveau". Je n'ai pas complètement compris le concept de fuite) Que devrais-je essayer de faire pour résoudre ce problème? – nikans

+0

S'il fuit, ça ne marche pas. Cela fonctionne seulement temporairement. :) Si vous regardez dans votre [SynonymAppDelegate initHistoryList], vous créez un nouveau HistoryDataController chaque fois. Mais alors vous ne le libérez pas. Si tout ce dont vous avez besoin de ce contrôleur est le tableau, vous devez conserver ce tableau, puis relâcher le contrôleur. J'espère que cela pourra aider. –

+0

Merci, je vais essayer d'appliquer ça :) – nikans

Questions connexes