【问题标题】:Dynamic c-style array. When to use retain, what to release and when to do it动态 c 样式数组。何时使用保留,释放什么以及何时使用
【发布时间】:2011-08-01 12:58:54
【问题描述】:

鉴于我上次的question,我决定从一个简单的类开始,以包含二维数组数据。

界面:

@interface DynamicTable
NSString ***data;
NSInteger _cols;
NSInteger _rows;
@end

初始化器:

-(id)initWithRows:(NSInteger)rows withCols:(NSInteger)cols {
    if (self = [super init]) {

        _rows = rows;
        _cols = cols;

        data = (NSString ***)malloc(_rows * sizeof(NSString **));
        for (int i = 0; i < _rows; ++i) {
            data[i] = (NSString **)malloc(_cols * sizeof(NSString *));
            for (int j = 0; j < _cols; ++j) {
                NSString *cell = [[NSString alloc] initWithFormat:@"%d",(i + j)];
                data[i][j] = cell;
            }
        }
    }
    return self;
}

我们是否保留?
此刻,我正在与一名实习生(之前曾为 iPhone 开发过,而我没有)进行过激烈的讨论,作业 data[i][j] = cell; 是否不应该数据[i][j] = [单元格保留];
第二个版本来自 SO 上的另一个示例。我已经从同一个问题中复制了 dealloc 例程。

我们会因任务而释放吗?
下一位代码负责在给定单元格中设置新值。问题再次出现,是否释放原始值(我已经认为这都是通过引用传递的)。

-(void)setValue:(NSString *)value atRow:(NSInteger)row atCol:(NSInteger)col {
    //NSString *cell = data[row][col];
    data[row][col] = value;
    //[cell release];
}

如你所见,我已经注释掉了应该释放原始值的位。

iPhone 中的整个内存管理似乎非常可怕。我已经在苹果网站和其他网站上阅读了很多关于此的内容,但是一次可以吸收很多内容。 具有清晰解释的小例子通常最适合我 LOL

回到我的问题:
从我的角度来看(不确定我是否正确),我应该释放放入给定单元格中的原始值。任何人都可以在这里确认我在正确的轨道上吗?

PS 我一直在尝试使用 Run with Performance Tool -> Leaks...但是我对 iPhone 知识的缺乏也让我望而却步。

【问题讨论】:

    标签: iphone objective-c xcode memory-management


    【解决方案1】:

    您正试图在 Objective-c 环境中编写一些 c 代码。如果我是你,我会坚持使用 Objective-c 并稀疏地使用 c。这就是它在 Objective-c 中的样子。

    @interface DynamicTable
    NSMutableArray *data;
    NSInteger _cols;
    NSInteger _rows;
    @end
    
    -(id)initWithRows:(NSInteger)rows withCols:(NSInteger)cols 
    {
        if (self = [super init]) 
        {
            _rows = rows;
            _cols = cols;
    
            data = [[NSMutableArray alloc] init]; //Release in dealloc method
    
            for (int i = 0; i < _rows; ++i) 
            {
                NSMutableArray *cells = [NSMutableArray array]; //Auto released
    
                for (int j = 0; j < _cols; ++j) 
                {
                    NSString *cell = [[NSString alloc] initWithFormat:@"%d",(i + j)];
                    [cells addObject:cell]; //Auto retains
                    [cell release]; //Release
                }
    
                [data addObject:cells];
            }
        }
        return self;
    }
    

    这就是你在访问器中要做的事情。

    -(void)setValue:(NSString *)value atRow:(NSInteger)row atCol:(NSInteger)col 
    {
        [[data objectAtIndex:row] insertObject:value atIndex:col]; //Auto retained
    }
    

    【讨论】:

    • 我不得不承认,这看起来比我写的要好得多。尽管我使用的示例还包括一个 NSMutableArray 示例,但投票选出的最佳答案是使用 c 样式数组的那个。一个原因与使用 data[row][col] 访问单个单元格的方便性有关。提到的另一个原因是速度,但我认为除非我们谈论数千个单元(这不会发生),否则没有人可以真正衡量真正的性能影响。我至少投票这个 +1,如果没有其他人有其他答案,我会接受它。
    • 我仍然对整个保留/释放的事情感兴趣,并且我最初的想法是否正确(例如,在单元格分配中使用保留并在设置新值时释放单元格的先前值)。
    • 这很难,因为您来自非客观 c/可可背景。如果你要做 iPhone 开发,学习objective-c/cocoa 也不错。
    • @djBO 我在回答中回答了您的保留/释放问题。这个例子是你想要实际实现你的代码的方式,除了data之外不需要保留任何东西,因为NSMutableArray会保留你添加到它的任何东西。最大的区别将是 dealloc 方法。这个例子只是 [data release] 来释放所有创建的字符串,我的例子基于你的 C 数组需要更多的工作。
    • @David & Joe: 我不能 +2 :( 最后,我重写了我的代码并实现了这个解决方案,因为它更合适。非常感谢你们!这有让人大开眼界……
    【解决方案2】:

    我同意 David,坚持使用 Objective-C,但我会回答您最初的问题,因为这可能会帮助您过渡到 Objective-C。

    第一个例子是正确的。以下返回一个保留的字符串,因为您调用了 alloc/init。

    NSString *cell = [[NSString alloc] initWithFormat:@"%d",(i + j)];
    data[i][j] = cell;
    

    您的dealloc 电话将与此类似

    -(void)dealloc
    {
        for(int i = 0; i < _rows; ++i)
        {
            for(int j = 0; j < _cols; ++j)
            {
                [data[i][j] release];
            }
            free(data[i]);
        }
        free(data);
    
        [super dealloc];
    }
    

    现在对于您的第二个示例,您需要保留该值但还需要释放之前的值。

    -(void)setValue:(NSString *)value atRow:(NSInteger)row atCol:(NSInteger)col {
        [value retain]; //retain in case value is the same
        [data[row][col] release];
        data[row][col] = value;
    }
    

    我不认为 Memory Management 在 Objective-C 中是可怕的,除了极少数例外情况(-[NSAutoreleasePool drain] 浮现在脑海中),实际上只有几条基本规则需要遵循。

    【讨论】:

    • +1,尽管你的 setter 应该在发布之前确保新值和旧值不相同。如果它们相同并且该对象是该值的唯一所有者,那么您的 setter 将导致崩溃。
    • 你完全正确!我修复了它,我在实现@dynamic 属性时没有犯这个错误,但不知何故忘记了:(
    • +1,非常感谢您提供这个完美的示例。尽管我已将代码重写为 David 的解决方案,但我接受了这个答案,因为它完美地解释了我的问题。而且我提到“可怕”并不是什么坏事:)我只是在很短的时间内掌握了这么多东西。
    猜你喜欢
    • 2011-05-04
    • 1970-01-01
    • 2010-09-09
    • 2015-01-02
    • 1970-01-01
    • 2012-09-27
    • 2011-09-06
    • 2020-09-29
    • 2017-06-01
    相关资源
    最近更新 更多