objective-c 声明、分配、加载和释放 NSMutableArray 的正确方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2308053/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 22:58:52  来源:igfitidea点击:

The correct way to declare, alloc, load, and dealloc an NSMutableArray

objective-ciphonensmutablearraydealloc

提问by Bonnie

I declare my array in my *.h file:

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

@interface aViewController: UIViewController
{
   NSMutableArray *anArray;    // You will need to later change this many times.
}
@end

I alloc memory for it my *.m file:

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

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

I click a test-button to load my array (eventually it will need to load DIFFERNT values on each click):

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

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

And I free it here:

我在这里释放它:

-(void) dealloc
{
   [anArray release];
   [super dealloc];
}

Does that all look ok?

这一切看起来好吗?

Because it crashes when I later run this code:

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

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

Not sure why a simple "NSLog() and count" would crash everything.

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



Dirk,

短剑,

Let me put it this way: I have a HUGEmisunderstanding of pointers, arrays, strings, and memory.

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

I've read everything I can find on it... but (yet) to find a simple, clear, easy-to-understand description.

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

Can you suggest one? (Hopefully less than 10 pages of reading.) Is there a reference that explains JUSTthis topic... and from a standpoint of "you have 12 years of coding experience... but NONE that ever dealt with allocating memory or pointers".)

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

So the variable-name is NOTthe way I refer to the object? Then why have it?

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

I'm used to many other languages that just do this:

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

myString = "this"
myString = "that"

myInt = 5
myInt = 15

(What could be simpler.)

(还有什么可以更简单的。)



Looks to me like this would be the easiest way to do this. (And it seems to work. But it is truly correct?)

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

Don't alloc any memory for my NSMutableArray initially.
Don't re-alloc any memory repeatedly.  (When I change my array's values.)
Don't release it repeatedly. (Before I change my array's values.)
Don't release it when I exit the program.

But:
Always remember to use RETAIN when I initially assign 
(and repeatedly reassign) new values to my anArray variable.


You are not loading your array with anArray = [NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil]; Instead, you are replacing it with a new instance, and worse: with an instance, whose reference is actually owned by some entity you do not control

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

Wow. So I could have 20 arrays... all called the same name: anArray... and they would be all different? (There's no such thing as a GLOBAL array?)

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

etc. In order to clear out old values, the method removeAllObject may be handy. There are also mutation methods, which may be used to add multiple values at once.

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

So... first I have to "remove all the objects"... and then I can call ONEmethod it re-add all my new values.

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

anArray = [[NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil] retain]; instead of the alloc/init sequence.

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

Wow. I thought nothing could be stored in an array without alloc'ing space for it.

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

If you really intend to replace the entire array, you may want to consider using properties

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

How would I do that using properties?
What would be the correct way to do something like this:

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

> anArray = [NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil];
> anArray = [NSMutableArray arrayWithObjects:@"four", @"five", @"six", nil];

Just like I would do:

就像我会做的那样:

x = 12;
x = 24;


Wow. I REALLYhave totally misunderstand everything about strings, arrays, and memory. I thought the "easy way" was to alloc ONCE... use the mutable array... change it as much as you want... and free it ONCE.

哇。我真的完全误解了关于字符串、数组和内存的一切。我认为“简单的方法”是分配一次……使用可变数组……随心所欲地改变它……然后释放一次。

The problem with doing so is that this new array isn't retained,

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

I would think the old array would be gone... and the new array could be used. (But I guess not.)

我认为旧的数组会消失......并且可以使用新的数组。(但我想不是。)

Further, you have a memory leak because you never freed the original array.

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

I was thinking the old array wasn't suppose to be freed... I'm not done with it... I just wish to CHANGE it to contain my new values. (But I guess not.)

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

but one is to use [anArray release];

但一种是使用 [anArray release];

I was thinking that would cause me to release the memory I allocated... (but I guess not)... and then I'd have to re-alloc more memory. (But I guess not.)

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

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

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

So I have to "retain" it... so it doesn't disappear out from under me? (Not sure why it would. Until Itell it to... in my final dealloc call.)

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

Another, probably more correct way to fix it would be to use the addObject: or addObjectsFromArray: NSMutableArray methods instead of constantly creating new arrays.

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

I only want to create ONEarray... and just use it as I want to. I never want to ADDto the array. I want to set it to my new values.

我只想创建一个数组……然后随心所欲地使用它。我从不想添加到数组中。我想将它设置为我的新值。

回答by Dirk

You are not loading your array with

你没有加载你的数组

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

Instead, you are replacing it with a new instance, and worse: with an instance, whose reference is actually owned by some entity you do not control (most likely, an NSAutoreleasePool.) The reference you properly owned, the one created by

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

[[NSMutableArray alloc] init]

is lost and will be leaked.

丢失并将被泄露。

Instead of replacing the entire array reference, mutate the one you have at your disposal already, using for example addObject:like

而不是更换整个数组引用的,变异您在您的处置已经是一个,使用例如addObject:

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

etc. In order to clear out old values, the method removeAllObjectmay be handy. There are also mutation methods, which may be used to add multiple values at once.

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

Alternatively, you can allocate the array using the construction method you already use, but be careful to retain it. In viewDidLoaddo

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

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

instead of the alloc/initsequence.

而不是alloc/init序列。

If you really intend to replace the entire array, you may want to consider using propertiesinstead of doing the reference counting manually.

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

回答by David Kanarek

The problem is anArray = [NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil];This replaces the array you initially created. The problem with doing so is that this new array isn't retained, so you lose it as soon as the method returns. Further, you have a memory leak because you never freed the original array.

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

There are several ways to fix this, but one is to use [anArray release]; anArray = [[NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil] retain];instead.

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

Another, probably more correct way to fix it would be to use the addObject:or addObjectsFromArray:NSMutableArraymethods instead of constantly creating new arrays.

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

回答by Constantino Tsarouhas

Remember this simple memory rule: only release objects you own. You own objects only when you create them using:

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

  • init(this method creates a new object with a retain count of 1)
  • new(this method is the same as using alloc and init)
  • copy(this method creates a new object with a retain count of 1 and with the contents of the receiver of the method)
  • retain(this method increases the retain count with 1)
  • init(此方法创建一个保留计数为 1 的新对象)
  • new(此方法与使用 alloc 和 init 相同)
  • copy(此方法创建一个保留计数为 1 且包含该方法接收者内容的新对象)
  • retain(此方法将保留计数增加 1)

The system deallocates automatically objects with a retain count of zero. You have to releaseevery object you own after you're done with it. If you releasetoo soon, you get a dangerous situation. If you don't releaseyour object when you're done with it, you get a leak.

系统dealloc自动处理保留计数为零的对象。完成后,您必须拥有自己的release每个对象。如果你release太早,你会遇到危险的情况。如果您在完成后不使用release对象,则会出现泄漏。

A pointer is a special object that refers to some object in memory. It's basically a memory address (and some other data). If you want to use an object, you have to allocate memory for it and then initialize. You assign (by using the =sign) to a pointer.

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

string = [[NSString alloc] init];

stringnow has a retain count of one. But because NSStringis an immutable object, it can't be changed after initialization. One way to assign stringa value is by doing it while initializing it.

string现在保留计数为 1。但是因为NSString是一个不可变对象,所以初始化之后就不能改变了。赋值string的一种方法是在初始化时进行赋值。

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

If you need to change stringregularly, you can use another class that is mutable: NSMutableString. But still, the only way to change them is in a message.

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

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

Just to note, this following code is wrongand results in a memory leak.

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

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

In the first line, stringis assigned to a newly created object. In the second one, stringis assigned to another string. You lose the reference to the newly created object and you get a leak: you can't release an object you don't have a reference to.

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

You don't get a problem when you do this with integers (inttype), because it's a "native" object. The Objective-C Runtime associates those data types directly with their value, not a pointer.

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

int1 = 4;
int1 = 5;

Note 1.Don't forget to always tell the runtime what type your pointer is. If you want to use string, you have to define it first in your header (if it's public) or implementation (if you want it hidden from other methods). Then you can use the name freely.

注意 1.不要忘记始终告诉运行时您的指针是什么类型。如果你想使用string,你必须首先在你的头文件(如果它是公开的)或实现(如果你希望它对其他方法隐藏)中定义它。然后您可以自由使用该名称。

NSString *string;

The star tells the runtime it's a pointer. For native types, there no pointer, so you get this.

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

int int1;

Note 2.Arrays (and dictionaries, etc.) behave all like NSStringin that they have both immutable and mutable variants.

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

Note 3.Most classes have special methods that allocate, initialize and autorelease all at once.

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

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

An autoreleased object doesn't need manual releaseas the system will releaseit for you after a while. It's very handy in situations where you need an object only for the duration of the method or between methods, not as a permanent part of an object. When you autoreleasesome object on the main thread (in an app with a GUI), it will be released when the event loop finishes the current loop (it finishes when some event is processed). Read more about Autorelease Pools in Apple's docs.

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

I hope I help everyone who doesn't understand well what pointers are. I myself had problems for a few months until I experimented heavily. :-)

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