таблица прокрутки: сообщение отправлено на освобожденный экземпляр - PullRequest
0 голосов
/ 14 ноября 2010

Я уже некоторое время танцую с бубном, но до сих пор не знаю, в чем причина этой ошибки.У меня есть tableView с историей пользовательских запросов данных из базы sqlite.Я новичок в разработке для iPhone, поэтому мой код может быть немного чрезмерным.Иерархия:

  • HistoryModel объект-модель с некоторыми методами инициализации

  • HistoryDataController получаетданные из базы данных и представляет массив объектов HistoryModel

  • HistoryViewController подкласс UITableView, отображает данные

  • AppDelegate там я изначально храню массив объектов HistoryModel (получая его из HistoryDataController) для его доступа к HistoryViewController.

Проблема заключается в том, что при прокрутке таблицыили откройте вкладку с ним во второй раз - она ​​вылетает с - [CFString retain]: сообщение отправлено на освобожденный экземпляр

Код:

HistoryModel.h довольно ненужный класс для этого случая, но я хочу, чтобы это повторялось в нескольких идентичных случаях, но немного сложнее

@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использовать сущность этого класса в качестве получателя данных и хранилища для объектов HistoryModel (в свойстве 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 подкласс UITableViewController, получает данные, хранящиеся в свойстве AppDelegate, и отображается в таблице

@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 при открытии вкладки истории, он получает данные свойства historyList, которое было сформировано 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.Извините за столько кода, но я считаю, что это все, что нужно.В результате половины дня, потраченного на этот вопрос, я могу догадаться, что эта проблема каким-то образом связана с сущностью HistoryModel, потому что, когда я удаляю «сохранить» для word @property, ошибка переключается на - [CFString isEqualToString:]: сообщение отправлено на освобожденный экземпляр

Я не очень разбираюсь в управлении памятью, но я предполагаю, что HistoryModel объекты внутри historyEntry в HistoryViewController или в historyList в AppDelegate освобождает каким-либо образом при прокрутке таблицы или открытии вкладки во второй раз.Но это только мое предположение.Очень ценю помощь.

1 Ответ

1 голос
/ 15 ноября 2010

У вас определенно есть проблема в - [HistoryModel initWithWord] Вы должны сохранить (или еще лучше скопировать) передаваемую строку.

Я бы написал так:

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

Есть люди, которые скажут, что использование setter в вашем init не является хорошей практикой. Я не из этого лагеря. Но в любом случае вам нужно сохранить или скопировать эту строку.

Тогда у вас возникает похожая проблема в делегате приложения, когда вы пропускаете каждый HistoryDataController при создании нового. (и это происходит каждый раз, когда появляется табличное представление). И вам действительно следует также сохранить этот массив (хотя это еще не вызвало проблемы, потому что вы утекли HistoryDataControllers и поэтому до сих пор маскируете эту проблему).

Мой общий совет: не откладывайте управление памятью. Вернуться позже и попытаться сделать это правильно - сложно и подвержено ошибкам даже для опытного разработчика. Гораздо проще встроить правильные методы управления памятью в код по мере его написания. Это означает, что стоит потратить время на прочтение руководства по управлению памятью, прежде чем приступить к написанию чего-либо подобного. Вы сэкономите много времени и разочарований.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...