Цель c, утечка памяти, чтение из sqlite и присвоение значений NSDictionary и NSAarray
У меня есть список магазинов в файле ListController. Я установил базу данных sqlite, в которой храню 60 магазинов. В верхней части списка у меня есть панель поиска.
Я создал класс DataController, который отвечает за загрузку и хранение данных в БД.
@interface DataController : NSObject {
sqlite3 *database;
NSArray *shops;
NSDictionary* dictionaryOfShops;
}
@property (nonatomic, retain) NSDictionary *dictionaryOfShops;
@property (nonatomic, retain) NSArray* shops;
-(void)initializeShops;
Метод initializeShops загружает данные из базы данных и сохраняет результаты в 2 подпорках следующим образом:
-(void)initializeShops{
[dictionaryOfShops release];
[shops release];
NSMutableDictionary *dictionary = [[[NSMutableDictionary alloc] init] autorelease];
if (sqlite3_open(....))
NSString *query = ....
if (sqlite3_prepare_v2(database, [query UTF8String],-1, &statement, nil) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW) {
int rId = sqlite3_column_int(statement, 0);
char *rName = (char *)sqlite3_column_text(statement, 1);
Shop* s = [[Shop alloc] init];
s.ID = rId;
if(sName != nil) s.Name = [NSString stringWithUTF8String:rName];
NSString *shopID = [[NSString alloc] initWithFormat:@"%d",s.ID];
[dictionary setObject:s forKey:shopID];
[shopID release];
[s release];
}
sqlite3_finalize(statement);
}
[query release];
dictionaryOfShops = [[NSDictionary alloc] initWithDictionary:dictionary];
shops = [[NSArray alloc] initWithArray:[dictionary allValues]];
dictionary = nil;
[dictionary release];
//Sorting
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"Name" ascending:YES];
NSArray *sortedList =[self.shops sortedArrayUsingDescriptors:[NSArray arrayWithObject:sort]];
self.shops = sortedList;
[sort release];
}
Проблема в том, что когда пользователь вводит какой-то текст в строку поиска, я изменяю значение запроса (добавляя LIKE....), а затем снова вызываю метод initializeShops. Этот второй раз приводит к множеству утечек (связанных со свойствами класса Shop), а также к утечкам NSDictionary и NSArray.
Перед тем, как отправить это вам, я попробовал разные решения, но по крайней мере это ничего не пропускает при первом вызове initilizeShops.
Я принимаю любое предложение, так как я действительно застрял на нем.
БОЛЬШЕ:
Действительно странная вещь - это управление памятью моего словаря var, а также магазинов с двумя реквизитами и dictionaryOfShops. С этим кодом
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
//add data to dictionary
dictionaryOfShops = [[NSDictionary alloc] initWithDictionary:dictionary];
shops = [[NSArray alloc] initWithArray:[dictionary allValues]];
[dictionary release]
Учитывая, что dictionaryOfShops и shop - это два синтезированных свойства (nonatomic, retain), как я могу изменить их значение без утечек?
В самый первый раз, когда я прохожу через этот метод, ничего не просачивается, со второго раза он начинает вытекать так много объектов (содержимого коллекций).
3 ответа
Хорошо, я нашел ошибку. В моем классе Shop я понимаю, что не реализовал метод
-(void)dealloc
Поэтому, когда я выпускаю старый словарь (чтобы подготовиться к новому назначению), все поля внутри него не освобождаются.
Первый вопрос: почему бы просто не использовать Core Data? Скорее всего, он будет быстрее, потребует меньше кода и будет значительно легче поддерживать со временем. Быть тупым; SQLite обманчиво сложен. Легко начать, исключительно трудно получить право.
В любом случае управление памятью dictionary
неправильно. Он не падает, потому что вы поменяли порядок назначения и выпуска nil, как предложил kennyTM. Я бы предложил не создавать автоматически выпущенный словарь.
В противном случае написанный код кажется на первый взгляд довольно непроницаемым. Так:
Можете ли вы предоставить еще немного кода? Что-нибудь интересное в памяти происходит в другом месте?
Вы используете многопоточность вообще (или NSOperationQueue)?
Работали ли вы под инструментом "Утечки" и извлекли обратные следы распределения определенных объектов, которые были пропущены?
dictionary = nil;
[dictionary release];
Пожалуйста, поменяйте местами эти 2 заявления. В этой форме это означает [nil release]
который не работает.