Массив объектов Objective-C (EXC_BAD_ACCESS) в TableViewController - PullRequest
1 голос
/ 17 апреля 2009

Я новичок в Objective-C, и я не могу понять, почему объекты NSString в моем массиве объектов Car, кажется, были освобождены.

Вот мой класс Car.m:


#import "Car.h"
@implementation Car
@synthesize categoryId;

- (id)initWithPrimaryKey:(NSInteger)pk categoryId:(NSNumber *)catId carName:(NSString *)n {
    if (self = [super init]) {
        primaryKey = pk;
        categoryId = catId;
        name = n;
    }

    return self;
}
- (void)dealloc {
    [name release];
    [categoryId release];

    [super dealloc];
}
- (NSInteger)primaryKey {
    return primaryKey;
}
- (NSString *)name {
    return name;
}
- (void)setName:(NSString *)aString {
    if ((!name && !aString) || (name && aString && [name isEqualToString:aString])) return;
    [name release];
    name = [aString copy];
}

@end

А вот и мой класс Simple_TableViewController.m. Переменная экземпляра listData правильно установлена ​​в viewDidLoad (). В отладчике свойство NSString * name каждого элемента массива не повреждено. Затем в любом другом методе listData поврежден. В нем есть все элементы Car с правильными значениями primaryKey и categoryId, но свойство NSString * name имеет значение «Invalid».


#import "Simple_TableViewController.h"
@implementation Simple_TableViewController

- (void)viewDidLoad {       
    NSMutableArray *array = [[NSMutableArray alloc] init];
    Database *database = [Database instance];

    array = [database getAllCars];
    [self setListData:array];
    [array release];
}
- (NSMutableArray *)listData {
    return listData;
}
- (void)setListData:(NSMutableArray *)newListData {
    if (listData != newListData) {
        [listData release];
        listData = [newListData mutableCopy];
    }
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}
- (void)dealloc {
    [listData release];
    [super dealloc];
}
- (NSInteger)tableView:(UITableView *)tableView
 numberOfRowsInSection:(NSInteger)section
{
    return [listData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
            cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *SimpleTableIdentifier = @"SimpleTableIdentifier";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SimpleTableIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero
                                                 reuseIdentifier:SimpleTableIdentifier] autorelease];
    }

    NSUInteger row = [indexPath row];
    Car *car = [listData objectAtIndex:row];

    cell.text = car.name;
    cell.font = [UIFont boldSystemFontOfSize:17];

    return cell;
}
- (NSInteger)tableView:(UITableView *)tableView
indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 0;
}
- (NSIndexPath *)tableView:(UITableView *)tableView
  willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSInteger row = [indexPath row];
    if (row == 0) {
        return nil;
    }

    return indexPath;
}
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSUInteger row = [indexPath row];

    NSString *message = [[NSString alloc] initWithFormat:@"You selected %@", [[listData objectAtIndex:row] name]];
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Row Selected!"
                                                                    message:message
                                                                  delegate:nil
                                                      cancelButtonTitle:@"Yes I Did"
                                                      otherButtonTitles:nil];
    [alert show];

    [message release];
    [alert release];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 35;
}

@end

Я возился с Зомби и держу это, пока мои пальцы не отвалились. Я покончил с вещами @property (nonatomic, retain) и @synthesize для переменной listData, и у меня все еще остается та же проблема.

Заранее благодарим за любой совет, который вы можете предложить!

Ответы [ 2 ]

3 голосов
/ 17 апреля 2009

В вашем методе initWithPrimaryKey: etc: вам необходимо сохранить эти значения или использовать точечную нотацию для их назначения (при условии, что они являются свойствами, объявленными с ключевым словом retain). Попробуйте это:

<pre> - (id)initWithPrimaryKey:(NSInteger)pk categoryId:(NSNumber *)catId carName:(NSString *)n { if (self = [super init]) { primaryKey = pk; categoryId =[catId retain]; name = [n retain]; }</p> <pre><code>return self;

}

Кроме того, и это просто проблема стиля, вы можете рассмотреть немного более подробных имен, чем 'n' и 'pk'. Ваше будущее само поблагодарит вас.

0 голосов
/ 17 апреля 2009

Немного не по теме - у Бена есть ответ, который вы ищете, но логика в вашем коде немного извилистая.

- (void)setName:(NSString *)aString {
    if ((!name && !aString) || (name && aString && [name isEqualToString:aString])) return;
    [name release];
    name = [aString copy];
}

На самом деле вам не нужно проверять (!name && !aString) это безопасная и распространенная практика - переназначить ноль на ноль и отправить сообщение об освобождении (или любое сообщение) на ноль. Во время выполнения замыкается последний, а оптимизатор удаляет первый. Если установка nil-имени является ошибкой, вы должны заявить, что aString не nil

Точно так же строки NSS очень хорошо оптимизированы. Не пытайтесь оптимизировать случай, когда вы устанавливаете имя автомобиля на имя, которое уже установлено. Фактически, ваша проверка [name isEqualToString:aString], которую вы берете каждый раз, когда кто-то устанавливает ненулевую строку, медленнее, чем выпуск и копирование, которых вы избегаете в меньшем количестве случаев.

Если вы проверите, что происходит при отправке копии на строку NSString, вы обнаружите, что она просто увеличивает количество сохраняемых данных. Обратите внимание, что это не так для NSMutableString по очевидным причинам; -)

Хорошее эмпирическое правило - оптимизируйте, когда у вас есть все функциональные возможности, и оптимизируйте только то, что медленное (или большое).

наконец, следуя комментариям Бена о присвоении имен, я бы переименовал aString в aCarName или что-то еще более информативное - опять же, ваше будущее я будет вам благодарно.

...