Objective-C / iOS: сообщение отправлено освобожденному экземпляру - PullRequest
1 голос
/ 30 марта 2011

Это мой первый пост на stackoverflow.com, поэтому, пожалуйста, будьте добры (перемотка назад);)

У меня есть приложение на основе навигации, целью которого является отображение сообщений блога (заголовка) в табличном представлении (с JSON). Проблема, с которой я столкнулся, возникла, когда ячейка вышла из экрана, а затем вернулась обратно. Я получал EXC_BAD_ACCESS (потому что я отправил сообщение в освобожденный экземпляр), поэтому я изо всех сил пытался понять, откуда оно пришло, и я наконец нашел решение. Но дело в том, что я не совсем понимаю, как возникает проблема. Вот почему мне нужен кто-то, чтобы просветить меня, я думаю, что это фундаментальное понимание!

Когда соединение с веб-службой JSON завершило загрузку, я анализирую код JSON, чтобы получить список сообщений в блоге (RecentPosts), затем я создаю объект BlogArticle для каждого сообщения (blogArticle), сохраняя его в MutableArray iVar (allEntries) и вставьте строку в табличное представление:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    [connection release];

    NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
    [responseData release];

    NSError *error;
    SBJsonParser *json = [[SBJsonParser new] autorelease];
    NSDictionary *recentPostsData = [json objectWithString:responseString error:&error];
    [responseString release];


    NSArray *recentPosts = [recentPostsData objectForKey:@"posts"];

    int i = 0;
    for (NSDictionary *post in recentPosts) {
        BlogArticle *blogArticle = [[BlogArticle alloc] initWithDictionary:post];
        [allEntries insertObject:blogArticle atIndex:i];
        [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:i inSection:0]] withRowAnimation:UITableViewRowAnimationRight];
        i++;
   }
}

Вот инициализация объекта BlogArticle, которая оказалась источником проблемы:

- (id)initWithDictionary:(NSDictionary *)article
{
    if (self = [super init])
    {
        // title = [[[article valueForKey:@"title"] gtm_stringByUnescapingFromHTML] copy];
        // title = [[NSString alloc] initWithString:[[article valueForKey:@"title"] gtm_stringByUnescapingFromHTML]];
        title = [[article valueForKey:@"title"] gtm_stringByUnescapingFromHTML];
    }

    return self;
}

Таким образом, каждый программист Objective-C, который не так болтлив, как я, может сказать, что заголовок никогда не выделяется до назначения. Если я раскомментирую одну из двух строк выше, она будет работать. Программа вылетает именно тогда, когда я пытаюсь инициализировать ячейку с этой переменной заголовка, здесь:

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

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }

    NSLog(@"indexPath.row = %i", indexPath.row);

    // Configure the cell.
    BlogArticle *article = [allEntries objectAtIndex:indexPath.row];

    cell.textLabel.text = article.title;

    return cell;
}

Теперь мне нужно понять, почему он выполняет компиляцию / работу без выделения iVar и где именно это вызывает проблемы (или где именно высвобождается содержимое заголовка, вызывающее сбой программы). Любой хороший ресурс (дружественный по отношению к новичкам) об управлении памятью в среде iOS был бы очень признателен.

Заранее спасибо:)

Ответы [ 2 ]

3 голосов
/ 30 марта 2011

Эта строка

title = [[article valueForKey:@"title"] gtm_stringByUnescapingFromHTML];

выделяет строку с автоматическим освобождением .По сути, подумайте, что автоматически выпущенная строка будет освобождена в конце метода (хотя она может длиться дольше, полезно думать об этом таким образом).

Вы знаете, что строка автоматически выпускается, потому что имяметода gtm_stringByUnescapingFromHTML не начинается с alloc, new, copy или mutableCopy.

Вы можете добавить retain к этому, чтобы остановить его автоматическое освобождение:

title = [[[article valueForKey:@"title"] gtm_stringByUnescapingFromHTML] retain];

Теперь вам принадлежит строка, и она не будет выпущена, пока вы не скажете.

Лучшее из известных мне резюме - собственная документация Apple здесь .

1 голос
/ 30 марта 2011

Ну, проблема в том, что вы должны инициализировать свой объект, если вы хотите управлять памятью самостоятельно. Почему вы должны управлять теперь памятью заголовка?

Довольно просто: Каждая ссылка на объект, которая хранится в массиве, наборе, словаре и т. Д., Управляется массивом, словарем и набором.

Если вы сейчас просто используете эту ссылку (написав: "title = ...") в своей ячейке, вы добавите ссылку и в ячейку. И теперь ячейка также отвечает за ссылку на объект. Поэтому, если tableView хочет освободить ваши ячейки, что время от времени будет происходить для экономии памяти, ячейка освободит ваш title-объект. И это может привести к тому, что NSDitionary будет довольно грустным, поскольку NSDictionary хочет позаботиться об объектах, хранящихся внутри себя.

Таким образом, вы можете написать следующее в методе tableView:

cell.textLabel.text = [article.title retain];

Или закомментированные строки вашего собственного метода. Это означает, что вы «поднимете» уровень хранения вашего объекта, и если он будет освобожден, сам уровень хранения будет уменьшен на единицу. Если уровень хранилища достигнет нуля, он будет полностью освобожден (это должно произойти, если ваша табличная ячейка будет освобождена И ваш NSDIctionary)

Надеюсь, я смогу вам немного помочь:)

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