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 が破損しています。すべての Car 要素に正しい primaryKey 値と categoryId 値が含まれていますが、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

私はゾンビこれをいじり、指が落ちるまでそれを保持します. listData 変数の @property (nonatomic、retain) と @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

トピックから少し外れます - ベンはあなたが探している答えを持っていますが、コードの一部のロジックは少し曲がりくねっています.

- (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 ではないことをアサートする必要があります

同様に、NSString は非常に最適化されています。車の名前を既に設定されている名前に設定している場合は、わざわざ最適化しないでください。[name isEqualToString:aString]実際、誰かが nil 以外の文字列を設定するたびに行うチェックは、少数のケースで回避しているリリースとコピーよりも遅くなります。

コピーを NSString に送信するとどうなるかを確認すると、保持カウントが増えるだけであることがわかります。明らかな理由により、これは NSMutableString には当てはまらないことに注意してください;-)

経験則として、すべての機能を備えているときに最適化し、遅い (または大きい) ものだけを最適化します。

最後に、ネーミングに関する Ben のコメントに続いて、aString を aCarName などのよりわかりやすい名前に変更します。

于 2009-04-17T07:22:44.703 に答える