0

我是 Objective-C 的新手,所以我在理解内存管理方面遇到了一些问题。我创建了一个没有 ARC 的项目(以了解内存管理),我想知道如何避免内存泄漏。

我用一些 C++ 代码解释。例如,我想用 3 个向量创建一个矩阵,所以在 C++ 中我们可以这样做(第一种方法):

Matrix mat(Vector(1, 1, 1), Vector(2, 2, 2));

在函数结束时,所有对象都被销毁并且没有内存泄漏

在 Objective-C 中,我们做这样的事情:

Matrix mat = [[Matrix alloc] init:[[Vector alloc] init:1:1:1]:[[Vector alloc] init:2:2:2]];

在 C++ 中是(第二种方法):

Matrix mat = new Matrix(new Vector(1, 1, 1), new Vector(2, 2, 2));

但是通过这种方式,我们无法破坏 2 个向量,因此我们会产生内存泄漏。

所以我的问题是,有没有办法在 Objective-C 中执行第一种方法?如果没有,我想我必须创建 2 个临时变量,其中包含 2 个向量并在矩阵初始化后释放,或者还有另一种方法可以做到这一点?

4

4 回答 4

2

除了您的语法不是真正符合 Obj-C 的事实之外,在这种情况下还有多种管理内存的选项。

注意:我假设您不想将参数存储到变量中,否则只需在将这些变量传递给构造函数后释放它们即可。使用 ARC,这并没有什么大的区别,因为您在任何情况下都不需要发布。

没有弧。工厂方法

Objective-C 中的工厂方法是按照惯例自动发布的。这个约定是如此强大,以至于即使是 ARC 也会期望这样的方法会被自动发布,所以要小心

Matrix *mat = [Matrix matrixWithVectors:[Vector vectorWithCoordinatesX:1 y:1 z:1],
                                        [Vector vectorWithCoordinatesX:1 y:1 z:1],
                                        [Vector vectorWithCoordinatesX:1 y:1 z:1], nil];

的实现vectorWithCoordinates,例如,应该类似于

+ (Vector *)vectorWithCoordinatesX:(CGFloat)x y:(CGFloat)y z:(CGFloat)z {
    return [[[Vector alloc] initWithCoordinatesX:x y:y z:z] autorelease];
}

没有弧。自动释放

如果因为内联创建参数而没有保留对参数的引用,则还可以显式地自动释放它们。

Matrix *mat = [[[Matrix alloc] initWithVectors:[[[Vector alloc] initWithCoordinatesX:1 y:1 z:1] autorelease],
                                               [[[Vector alloc] initWithCoordinatesX:1 y:1 z:1] autorelease],
                                               [[[Vector alloc] initWithCoordinatesX:1 y:1 z:1] autorelease], nil] autorelease];

在 ARC 中不需要发布,因为编译器会处理它。

所以两者

Matrix *mat = [Matrix matrixWithVectors:[Vector vectorWithCoordinatesX:1 y:1 z:1],
                                        [Vector vectorWithCoordinatesX:1 y:1 z:1],
                                        [Vector vectorWithCoordinatesX:1 y:1 z:1], nil];

Matrix *mat = [[Matrix alloc] initWithVectors:[[Vector alloc] initWithCoordinatesX:1 y:1 z:1],
                                              [[Vector alloc] initWithCoordinatesX:1 y:1 z:1],
                                              [[Vector alloc] initWithCoordinatesX:1 y:1 z:1], nil];

是正确的。

我在这里的假设也是Matrix构造函数将任意数量的向量作为参数,nil终止。

于 2012-12-30T12:06:51.397 回答
1

您是正确的,您需要使用临时变量来正确释放对象。

通常在 pre-ARC 代码中,你会使用 autorelease 代替:

Matrix mat = [[Matrix alloc] init:[[[Vector alloc] init:1:1:1] autorelease] :[[[Vector alloc] init:2:2:2] autorelease]];

或者,更好的是,您可以为 Vector 添加一个方便的方法:

+ (Vector*) vector:(int)a :(int)b :(int)c
{
    return [[[Vector alloc] init:a :b :c] autorelease];
}

然后使用它:

Matrix mat = [[Matrix alloc] init:[Vector vector:1 :1 :1] :[Vector vector:2 :2 :2]];

(顺便说一句,在冒号前不带单词来命名方法是一种不好的形式——很难阅读。)

于 2012-12-30T11:59:29.197 回答
0

您的 Objective-C 代码是错误的。你的假设是对的

所以我的问题是,有没有办法在 Objective-C 中执行第一种方法?如果没有,我想我必须创建 2 个临时变量,其中包含 2 个向量并在矩阵初始化后释放,或者还有另一种方法可以做到这一点?

另一种方法是使用类方法来获取自动释放的对象。这些方法以加号开头。或者你也可以自己自动释放向量。

[[[Vector alloc] init:1:1:1] autorelease];

顺便说一句:在 Objective-C 中你不应该使用未命名的参数。所以你的初始化应该是这样的:

[[[Vector alloc] initWithX:1 y:1 z:1] autorelease];

但我强烈建议使用 ARC 并停止担心内存管理。

于 2012-12-30T11:56:07.930 回答
0

您需要释放您分配的所有对象,如 C++ new 和 delete。因此,一种方法是如您所说创建临时变量然后释放它们。

然而,当包含对象的自动释放池被释放时,也有 autorelease 来释放对象,例如,如果你没有创建自己的池,在主 NSApplication 循环中。在这种情况下,这允许您在线进行内存管理。

所以

Matrix mat = [[[Matrix alloc] init:[[[Vector alloc] init:1:1:1]autorelease]
                  :[[[Vector alloc] init:2:2:2]autorelease]
                  autorelease];

请参阅Apple 关于内存管理的文档作为开始。

我会看一些例子来学习这个机制,但是去 ARC 做任何实际的工作——你可能需要了解底层的发布机制来调试。

于 2012-12-30T12:00:46.910 回答