6

我在 *.h 文件中声明了我的数组:

@interface aViewController: UIViewController
{
   NSMutableArray *anArray; // 您稍后需要多次更改。
}
@结尾

我为它分配内存我的 *.m 文件:

-(无效)viewDidLoad
{
   anArray = [[NSMutableArray alloc] init];
}

我点击一个测试按钮来加载我的数组(最终每次点击都需要加载不同的值):

   anArray = [NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil];

我在这里释放它:

-(无效) 解除分配
{
   [anArray 发布];
   [超级释放];
}

这一切看起来都好吗?

因为当我稍后运行此代码时它会崩溃:

   NSLog(@"%d", [anArray count]);

不知道为什么一个简单的“NSLog() 和计数”会使一切崩溃。


短剑,

让我这样说吧:我对指针、数组、字符串和内存有一个巨大的误解。

我已经阅读了我能找到的所有内容......但是(尚未)找到一个简单、清晰、易于理解的描述。

你能推荐一个吗?(希望不到 10 页的阅读量。)是否有参考资料可以解释这个主题......从“你有 12 年的编码经验......但没有一个处理过分配内存或指针”的角度来看。 )

所以变量名不是我引用对象的方式吗?那为什么会有呢?

我已经习惯了许多其他语言,只是这样做:

我的字符串 = “这个”
myString = "那个"

我的整数 = 5
我的整数 = 15

(还有什么更简单的。)


在我看来,这将是最简单的方法。(它似乎有效。但它真的正确吗?)

最初不要为我的 NSMutableArray 分配任何内存。
不要重复重新分配任何内存。(当我更改数组的值时。)
不要反复释放它。(在我更改数组的值之前。)
当我退出程序时不要释放它。

但:
当我最初分配时,永远记得使用 RETAIN
(并反复重新分配)新值给我的 anArray 变量。

你没有加载你的数组 anArray = [NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil]; 相反,您将其替换为一个新实例,更糟糕的是:使用一个实例,其引用实际上由您无法控制的某个实体拥有

哇。所以我可以有 20 个数组……都叫同一个名字:anArray……而且它们都不同?(没有 GLOBAL 数组这样的东西吗?)

等为了清除旧值,removeAllObject 方法可能很方便。还有变异方法,可用于一次添加多个值。

所以......首先我必须“删除所有对象”......然后我可以调用一个方法来重新添加我所有的新值。

anArray = [[NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil] 保留]; 而不是 alloc/init 序列。

哇。我认为如果不为其分配空间,就无法将任何内容存储在数组中。

如果您真的打算替换整个数组,您可能需要考虑使用属性

我将如何使用属性来做到这一点?
做这样的事情的正确方法是什么:

> anArray = [NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil];
> anArray = [NSMutableArray arrayWithObjects:@“四”,@“五”,@“六”,无];

就像我会做的那样:

x = 12;
x = 24;

哇。我真的完全误解了关于字符串、数组和内存的一切。我认为“简单的方法”是分配一次......使用可变数组......尽可能多地改变它......并释放它一次。

这样做的问题是没有保留这个新数组,

我认为旧阵列会消失......并且可以使用新阵列。(但我猜不是。)

此外,您有内存泄漏,因为您从未释放原始数组。

我在想旧数组不应该被释放......我还没有完成它......我只是希望改变它以包含我的新值。(但我猜不是。)

但一种是使用 [anArray release];

我在想这会导致我释放我分配的内存......(但我猜不是)......然后我必须重新分配更多内存。(但我猜不是。)

anArray = [[NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil] 保留];

所以我必须“保留”它……所以它不会从我下面消失?(不知道为什么会这样。直到告诉它......在我最后的 dealloc 调用中。)

另一种可能更正确的修复方法是使用 addObject: 或 addObjectsFromArray: NSMutableArray 方法,而不是不断创建新数组。

我只想创建一个数组......然后随意使用它。我从不想添加到数组中。我想将其设置为我的新值。

4

3 回答 3

11

你没有加载你的数组

anArray = [NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil];

相反,您正在用一个新实例替换它,更糟糕的是:使用一个实例,其引用实际上由您无法控制的某个实体拥有(很可能是一个NSAutoreleasePool。)您正确拥有的引用,由

[[NSMutableArray alloc] init]

丢失并将被泄露。

与其替换整个数组引用,不如改变您已经拥有的引用,例如addObject:使用

[anArray addObject: @"one"]
[anArray addObject: @"two"]

等为了清除旧值,该方法removeAllObject可能很方便。还有变异方法,可用于一次添加多个值。

或者,您可以使用您已经使用的构造方法分配数组,但要小心保留它。在viewDidLoad

anArray = [[NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil] retain];

而不是alloc/init序列。

如果您真的打算替换整个数组,您可能需要考虑使用属性而不是手动进行引用计数。

于 2010-02-22T00:14:34.047 回答
4

问题是anArray = [NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil];这替换了您最初创建的数组。这样做的问题是这个新数组没有被保留,所以一旦方法返回,你就会丢失它。此外,您有内存泄漏,因为您从未释放原始数组。

有几种方法可以解决此问题,但其中一种是[anArray release]; anArray = [[NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil] retain];改用。

另一种可能更正确的修复方法是使用addObject:oraddObjectsFromArray: NSMutableArray方法,而不是不断创建新数组。

于 2010-02-22T00:15:51.797 回答
3

记住这个简单的内存规则:只释放你拥有的对象。只有当您使用以下方法创建对象时,您才拥有对象:

  • init (此方法创建一个保留计数为 1 的新对象)
  • new (此方法与使用 alloc 和 init 相同)
  • copy (此方法创建一个保留计数为 1 的新对象,以及方法接收者的内容)
  • retain (此方法将保留计数增加 1)

系统dealloc自动吃掉保留计数为零的对象。完成后,您必须拥有您拥有的release每个对象。如果你release太快,你会遇到危险的情况。如果你在完成时没有release你的对象,你会得到一个泄漏。

指针是一个特殊的对象,它指向内存中的某个对象。它基本上是一个内存地址(和一些其他数据)。如果你想使用一个对象,你必须alloc为它吃掉内存,然后再进行initialize。您将(通过使用=符号)分配给指针。

string = [[NSString alloc] init];

string现在保留计数为 1。但由于NSString是不可变对象,初始化后无法更改。分配string值的一种方法是在初始化时进行。

string = [[NSString alloc] initWithString: @"Hello, World!"];

如果需要string定期更改,可以使用另一个可变类:NSMutableString. 但是,改变它们的唯一方法是在消息中。

string = [[NSMutableString alloc] initWithString: @"Initial string"];
[string setString: @"Modified string"];

请注意,以下代码是错误的,会导致内存泄漏。

string = [[NSMutableString alloc] initWithString: @"Initial string"];
string = @"Modified string";

在第一行,string分配给一个新创建的对象。在第二个中,string分配给另一个字符串。你失去了对新创建对象的引用,你得到了一个泄漏:你不能释放一个你没有引用的对象。

当您使用整数(类型)执行此操作时,您不会遇到问题int,因为它是一个“本机”对象。Objective-C 运行时将这些数据类型直接与其值相关联,而不是指针。

int1 = 4;
int1 = 5;

注意 1.不要忘记总是告诉运行时你的指针是什么类型。如果你想使用string,你必须首先在你的标题(如果它是公共的)或实现中定义它(如果你希望它对其他方法隐藏)。然后你就可以自由地使用这个名字了。

NSString *string;

星号告诉运行时它是一个指针。对于本机类型,没有指针,所以你得到了这个。

int int1;

注意 2.数组(和字典等)NSString的行为都像它们具有不可变和可变变体一样。

注意 3.大多数类都有特殊的方法,可以同时分配、初始化和自动释放。

NSArray *myArray = [NSArray arrayWithObjects: @"Butter", @"Milk", @"Honey", nil];

自动释放的对象不需要手动release,因为系统会release在一段时间后为您提供。在您仅在方法期间或方法之间需要对象而不作为对象的永久部分的情况下,它非常方便。当您autorelease在主线程(在具有 GUI 的应用程序中)上的某个对象时,它将release在事件循环完成当前循环时为 d(当处理某些事件时它完成)。在 Apple 的文档中阅读有关自动释放池的更多信息。

我希望我能帮助所有不太了解指针是什么的人。我自己有几个月的问题,直到我进行了大量的实验。:-)

于 2011-05-15T00:16:56.527 回答