1

我是 Objective-C 的新手,我不明白为什么我的 Car 对象数组中的 NSString 对象似乎已被释放。

这是我的 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 都已损坏。它包含所有具有正确 primaryKey 和 categoryId 值的 Car 元素,但 NSString *name 属性为“无效”。


#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

我已经摆弄了 Zombie 这个并保留它直到我的手指掉下来。我取消了 listData 变量的@property(非原子,保留)和@synthesize 东西,但我仍然遇到同样的问题。

提前感谢您提供的任何建议!

4

2 回答 2

3

在您的 initWithPrimaryKey:etc: 方法中,您需要保留这些值,或者使用点符号来分配它们(假设它们是使用 retain 关键字声明的属性)。试试这个:

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

return self;

}

此外,这只是一个样式问题,您可能会考虑“n”和“pk”更冗长的名称。你未来的自己会感谢你。

于 2009-04-17T04:14:10.023 回答
0

稍微偏离主题 - Ben 有您正在寻找的答案,但您的某些代码中的逻辑有点曲折。

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

您真的不需要检查(!name && !aString)将 nil 重新分配到 nil 并将释放消息(或任何消息)发送给 nil 是否安全且常见的做法。运行时使后者短路,优化器将删除前者。如果设置 nil 名称是错误的,您应该断言 aString 不是 nil

同样,NSStrings 也得到了很好的优化。不要费心优化将汽车名称设置为已设置名称的情况。[name isEqualToString:aString]事实上,每次有人设置非零字符串时您进行的检查比您在少数情况下避免的发布和复制要慢。

如果您检查将副本发送到 NSString 时会发生什么,您会发现它只会增加保留计数。请注意,由于明显的原因,这不适用于 NSMutableString ;-)

A good rule of thumb - optimise when you have all functionality and only optimise what is slow (or big).

finally, following on from Ben's comments about naming, I'd rename aString to aCarName or something else more descriptive - again, your future self will thank you.

于 2009-04-17T07:22:44.703 回答