Странный сбой (EXC_BAD_ACCESS) прокрутки UITableView повторного входа в приложение после фона - PullRequest
0 голосов
/ 17 декабря 2010

Я использую UITableView со стандартной ячейкой с субтитрами и UIImageView. Прокрутка в порядке, пока я не выйду из приложения. Затем он идет в фоновом режиме (я ничего не делаю в методах делегата backgroun), и когда я перезапускаю приложение в том же представлении с uitable, прокрутка в порядке для некоторых строк, а затем происходит сбой приложения в методе:

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

код метода:

static NSString *CellIdentifier = @"Cell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil) {

    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];

  ALog(@"TRACE");

    }

  // Configure the cell...

 cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

 NSDictionary *cellContent = (NSDictionary *)[self.items objectAtIndex:indexPath.row];

 Restaurant * r = (Restaurant *)[cellContent valueForKey:@"ristorante"];

 cell.textLabel.textColor = [UIColor colorWithRed:245.0 green:245.0 blue:245.0 alpha:0.8];

 cell.textLabel.text = r.nome;

 cell.detailTextLabel.textColor = [UIColor lightTextColor];

 cell.detailTextLabel.text = [r.indirizzo convertToString];

 UIImage *img = r.tipo.image; //[UIImage imageNamed:@"loghetto_pne.png"];

 cell.imageView.image = img; 

  //cell.imageView.clipsToBounds = YES;

  //cell.imageView.contentMode = UIViewContentModeScaleAspectFit;

 float sw= 48/img.size.width;

 float sh= 48/img.size.height;

 cell.imageView.transform = CGAffineTransformMakeScale(sw,sh);

  //[img release];



    return cell;

Сбой в строке:

cell.imageView.image = img;

Из трассировки стека я вижу, что выполнение идет по некоторому внутреннему фреймворковому коду, а затем происходит сбой. Исключение не всегда одинаково (часто это число CATransaction -> объект не отвечает на селектор и т. Д.)

Код для ресторана и типологии:

#import <Foundation/Foundation.h>
@class Zona;
@class Indirizzo;
@class Tipologia;

@interface Restaurant : NSObject {

@private
    NSUInteger idx;
    NSString *nome;
    NSString *telefono;
    Indirizzo *indirizzo;
    Zona *zona;
    Tipologia *tipo;

}

-(id)initWithIdx:(NSUInteger)index name:(NSString *)ristoName tel:(NSString *)ristoTel address:(Indirizzo *)ristoAdd zone:(Zona *)ristoZone;

@property (nonatomic) NSUInteger idx;
@property (nonatomic,retain) NSString *nome;
@property (nonatomic,retain) NSString *telefono;
@property (nonatomic,retain) Indirizzo *indirizzo;
@property (nonatomic,retain) Zona *zona;
@property (nonatomic,retain) Tipologia *tipo;


@end

Реализация ресторана:

#import "Restaurant.h"
#import "Zona.h"
#import "Indirizzo.h"
#import "Macro.h"


@implementation Restaurant

@synthesize idx, nome, indirizzo, telefono, zona, tipo;

-(id)initWithIdx:(NSUInteger)index name:(NSString *)ristoName tel:(NSString *)ristoTel address:(Indirizzo *)ristoAdd zone:(Zona *)ristoZone {
    [self init];
    bool error = NO;
    if (self) {
        idx = index;
        nome = [ristoName retain];
        telefono = [ristoTel retain];
        indirizzo = [ristoAdd retain];
        zona = [ristoZone retain];
    }

    return (error) ? nil : self;
}

- (id)init {
    self = [super init];
    if (self) {
        idx = 0;
        nome = @"";
        telefono = @"";
        indirizzo = nil;
        zona = nil;
        tipo = nil;
    }
    return self;
}

- (void)dealloc {
    [nome release];
    [indirizzo release];
    [telefono release];
    [zona release];
    ALog(@"TRACE");
    [tipo release];
    ALog(@"TRACE");
    [super dealloc];
}

@end

Типология интерфейса и реализации:

#import <Foundation/Foundation.h>

typedef enum {
    kTipoRestUnknown = 0,
    kTipoRestRestaurant,
    kTipoRestBrunch,
    kTipoRestPizza,
    kTipoRestRegional,
    kTipoRestEthnic
} TipoRest;

@class ImageTest;

@interface Tipologia : NSObject {

@private    
    NSInteger idx;
    NSString *desc;
    UIImage *image;
    TipoRest type;
}

-(id)initWithIndex:(NSInteger) index description:(NSString *)descr ofType:(TipoRest) type;

@property (nonatomic) NSInteger idx;
@property (nonatomic) TipoRest type;
@property (nonatomic,retain) NSString *desc;
@property (nonatomic,retain) UIImage *image;


@end

#import "Tipologia.h"
#import "Macro.h"

@implementation Tipologia

@synthesize desc, idx, image, type;

#pragma mark -
#pragma mark Memory Management

-(id)initWithIndex:(NSInteger) index description:(NSString *)descr ofType:(TipoRest) type {
    self = [super init];
    if (self != nil) {
        self.idx = index;
        self.desc = descr;
        self.image = [UIImage imageNamed:@"immagineNA.png"];;
        self.type = type;
    }
    return self;
}

-(void)dealloc {
    [desc release];
    desc = nil;
    ALog(@"TRACE");
    [image release];
    image = nil;
    ALog(@"TRACE");
    [super dealloc];    
}

-(void)release {
    ALog(@"tipo.idx: %i, tipo.count: %i, tipo.imag: %@, tipo.img.count: %i", idx, [self retainCount], image, [image retainCount]);
    [super release];
}

РЕДАКТИРОВАТЬ 2 Какой-то другой код. Фрагмент, в котором я инициализирую изображения на основе типа

if (sqlite3_prepare_v2(db, queryStrTipo, -1, &query, NULL) == SQLITE_OK) {
        restImage = [UIImage imageNamed:@"rest.png"];
        pizzaImage = [UIImage imageNamed:@"pizza.png"];
        etnImage = [UIImage imageNamed:@"etnico.png"];
        brunchImage = [UIImage imageNamed:@"wineglass-blue.png"];

        while(sqlite3_step(query) == SQLITE_ROW) { 
            NSString *desc = [NSString stringWithUTF8String:(char *)sqlite3_column_text(query, 1)];
            tipo = [[Tipologia alloc] initWithIndex:sqlite3_column_int(query, 0)
                                                description:desc ofType:kTipoRestUnknown];
            ALog(@"tipo.idx: %i, retain count: %i",tipo.idx, [tipo retainCount]);
            if ([desc compare:kTipoDescRestaurant options:NSCaseInsensitiveSearch] == NSOrderedSame) {
                tipo.type = kTipoRestRestaurant;
                tipo.image = restImage;
            } else 
            if ([desc compare:kTipoDescPizza options:NSCaseInsensitiveSearch] == NSOrderedSame) {
                tipo.type = kTipoRestPizza;
                tipo.image = pizzaImage;
            } else
            if ([desc compare:kTipoDescEtnico options:NSCaseInsensitiveSearch] == NSOrderedSame) {
                tipo.type = kTipoRestEthnic;
                tipo.image = etnImage;
            } else
            if ([desc compare:kTipoDescBrunch options:NSCaseInsensitiveSearch] == NSOrderedSame) {
                tipo.type = kTipoRestBrunch;
                tipo.image = brunchImage;
            } else
            if ([desc compare:kTipoDescRegionale options:NSCaseInsensitiveSearch] == NSOrderedSame) {
                tipo.type = kTipoRestRegional;
            }


            dictionary = [[NSMutableDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithInt:tipo.idx], @"index", tipo.desc, @"desc", nil];
            [listaTipologie addObject:tipo];
            [listaTemp addObject:dictionary];
            ALog(@"tipo.idx: %i, retain count: %i",tipo.idx, [tipo retainCount]);
            [tipo release];
            [dictionary release];
        }
        [restImage release];
        [pizzaImage release];
        [etnImage release];
        [brunchImage release];
    }

Ответы [ 2 ]

1 голос
/ 17 декабря 2010

Я решил проблему.

UIImage imageNamed возвращает объект автоматического выпуска (я не знал об этом), и я использую его для выделения 4 переменных изображения, которые затем будут назначены свойству (через. Sintax), и я освобождаю их после назначения.

Build & Analyze сказал мне, что оператор release может быть неправильным, потому что я больше не являюсь владельцем объекта. Прокомментировал это, и авария погасла ...

Строки неисправности были последними в фрагменте «РЕДАКТИРОВАТЬ 2» моего вопроса.

Спасибо всем.

1 голос
/ 17 декабря 2010

Вам не хватает сохранения в r.tipo или r.tipo.image.

, если они оба являются синтезированными свойствами, убедитесь, что объявление свойства содержит сохранение.

ЕслиВы реализовали свои собственные методы получения и / или установки, проверьте, правильно ли вы сохраняете и освобождаете все.

Редактировать:

Я только что увидел новый код, который вы опубликовали.Ваша проблема в том, что вы выпускаете UIImages, которые не принадлежат вашему коду.Исключая всю условную логику, вы в основном делаете это:

//Incorrect
UIImage *myImagename = [UIImage imageNamed:@"foo.png"]
yourclass.image = restImage;
[myImagename release];

Это неверно, потому что вы никогда не вызывали alloc, copy или retain для объекта myImage.[UIImage imageMamed] возвращает автоматически выпущенный экземпляр UIImage.Это то же самое, что сделать это (также неверно):

//Incorrect
UIImage *myImagename = [[UIImage alloc] initWithImage:@"foo.png"] autorelease];
yourclass.image = restImage;
[myImagename release];

У вас есть два варианта.Либо управляйте выпуском самостоятельно:

UIImage *myImagename = [UIImage alloc] initWithImage:@"foo.png"];
yourclass.image = restImage;
[myImagename release];

Или позвольте автоматически выпущенному объекту делать свое дело:

UIImage *myImagename = [UIImage imageNamed:@"foo.png"]
yourclass.image = restImage;
//Note: no release needed on yourClass.

В вашем конкретном коде вы можете использовать второй подход, и он будет выглядеть так:

if (sqlite3_prepare_v2(db, queryStrTipo, -1, &query, NULL) == SQLITE_OK) {
        restImage = [UIImage imageNamed:@"rest.png"];
        pizzaImage = [UIImage imageNamed:@"pizza.png"];
        etnImage = [UIImage imageNamed:@"etnico.png"];
        brunchImage = [UIImage imageNamed:@"wineglass-blue.png"];

        while(sqlite3_step(query) == SQLITE_ROW) { 
            NSString *desc = [NSString stringWithUTF8String:(char *)sqlite3_column_text(query, 1)];
            tipo = [[Tipologia alloc] initWithIndex:sqlite3_column_int(query, 0)
                                                description:desc ofType:kTipoRestUnknown];
            ALog(@"tipo.idx: %i, retain count: %i",tipo.idx, [tipo retainCount]);
            if ([desc compare:kTipoDescRestaurant options:NSCaseInsensitiveSearch] == NSOrderedSame) {
                tipo.type = kTipoRestRestaurant;
                tipo.image = restImage;
            } else 
            if ([desc compare:kTipoDescPizza options:NSCaseInsensitiveSearch] == NSOrderedSame) {
                tipo.type = kTipoRestPizza;
                tipo.image = pizzaImage;
            } else
            if ([desc compare:kTipoDescEtnico options:NSCaseInsensitiveSearch] == NSOrderedSame) {
                tipo.type = kTipoRestEthnic;
                tipo.image = etnImage;
            } else
            if ([desc compare:kTipoDescBrunch options:NSCaseInsensitiveSearch] == NSOrderedSame) {
                tipo.type = kTipoRestBrunch;
                tipo.image = brunchImage;
            } else
            if ([desc compare:kTipoDescRegionale options:NSCaseInsensitiveSearch] == NSOrderedSame) {
                tipo.type = kTipoRestRegional;
            }


            dictionary = [[NSMutableDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithInt:tipo.idx], @"index", tipo.desc, @"desc", nil];
            [listaTipologie addObject:tipo];
            [listaTemp addObject:dictionary];
            ALog(@"tipo.idx: %i, retain count: %i",tipo.idx, [tipo retainCount]);
            [tipo release];
            [dictionary release];
        }
    }

Помните, золотое правило управления памятью iOS:

Если вы используете какой-либо метод со словом copy, alloc или new, вам нужен соответствующий выпуск.

И, конечно же, Руководство по программированию управления памятью Apple является окончательным ресурсом

...