我在我的* .h文件中声明我的数组:
@interface aViewController: UIViewController { NSMutableArray *anArray; // You will need to later change this many times. } @end
我为我的* .m文件分配内存:
-(void) viewDidLoad { anArray = [[NSMutableArray alloc] init]; }
我单击一个测试按钮来加载我的数组(最终它需要加载DIFFERNT值 每次点击):
anArray = [NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil];
我在这里释放它:
-(void) dealloc { [anArray release]; [super dealloc]; }
这一切看起来都好吗?
因为我以后运行此代码时崩溃了:
NSLog(@"%d", [anArray count]);
不确定为什么简单的“NSLog()和count”会使一切崩溃。
德克,
让我这样说吧:我对指针,数组,字符串和内存有一个巨大的误解。
我已经阅读了我能在其上找到的所有内容...但是(尚)找到一个简单,清晰,易于理解的描述。
你可以推荐一个吗? (希望阅读不到10页。) 是否有一个参考解释 JUST 这个主题...并且从“你有12年的编码经验......但没有处理过分配内存或指针”的观点来看。)所以变量名是 NOT 我引用对象的方式? 那为什么呢?
我已经习惯了许多其他语言:
myString = "this" myString = "that" myInt = 5 myInt = 15
(可能更简单。)
在我看来,这是最简单的方法。 (它似乎有效。但这是真的正确吗?)
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.
您没有加载数组 anArray = [NSMutableArray arrayWithObjects:@“one”,@“two”,@“three”,nil]; 相反,你用新的实例替换它,更糟糕的是:用一个实例替换它 引用实际上由您无法控制的某个实体拥有
哇。所以我可以拥有20个数组......所有的名字都叫同一个名字:anArray ......它们会有所不同吗? (没有GLOBAL数组这样的东西?)
等。为了清除旧值,方法removeAllObject可能很方便。 还有一些变异方法,可用于一次添加多个值。
所以......首先我必须“删除所有对象”......然后我可以调用 ONE 方法重新添加所有新值。
anArray = [[NSMutableArray arrayWithObjects:@“one”,@“two”,@“three”,nil] retain]; 而不是alloc / init序列。
哇。我认为没有任何东西可以存储在数组中而不为它分配空间。
如果您真的打算更换整个阵列,您可能需要考虑 使用属性
我如何使用属性呢?
做这样的事情的正确方法是什么:
> anArray = [NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil]; > anArray = [NSMutableArray arrayWithObjects:@"four", @"five", @"six", nil];
就像我一样:
x = 12; x = 24;
哇。我真的完全误解了字符串,数组和内存的一切。 我认为“简单方法”是分配ONCE ...使用可变数组...根据需要更改它...并释放它。
这样做的问题是不保留这个新数组,
我认为旧阵列将会消失......并且可以使用新阵列。 (但我猜不是。)
此外,您有内存泄漏,因为您从未释放原始数组。
我在想,旧的阵列不应该被释放......我没有完成它...我只是想改变它以包含我的新值。 (但我猜不是。)
但是一个是使用[anArray release];
我在想这会让我释放我分配的内存......(但我猜不是)......然后我必须重新分配更多的内存。 (但我猜不是。)
anArray = [[NSMutableArray arrayWithObjects:@“one”,@“two”,@“three”,nil] retain];
所以我必须“保留”它...所以它不会从我身下消失? (不知道为什么会这样。直到我告诉它......在我最后的dealloc电话中。)
另一种可能更正确的修复方法是使用addObject:或 addObjectsFromArray:NSMutableArray方法,而不是不断创建新数组。
我只想创建 ONE 数组......并且只是按照我的意愿使用它。 我从不想 ADD 到数组。我想将它设置为我的新值。
答案 0 :(得分: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
序列。
如果您真的想要替换整个阵列,您可能需要考虑使用properties而不是手动进行引用计数。
答案 1 :(得分:4)
问题是anArray = [NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil];
这会替换您最初创建的数组。这样做的问题是不保留这个新数组,所以一旦方法返回就会丢失它。此外,您有内存泄漏,因为您从未释放原始数组。
有几种方法可以解决此问题,但其中一种方法是使用[anArray release]; anArray = [[NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil] retain];
代替。
另一种可能更正确的解决方法是使用addObject:
或addObjectsFromArray:
NSMutableArray
方法,而不是不断创建新数组。
答案 2 :(得分:3)
请记住这个简单的内存规则:仅发布您拥有的对象。只有在使用以下方法创建对象时才拥有对象:
init
(此方法创建一个保留计数为1的新对象) new
(此方法与使用alloc和init相同) copy
(此方法创建一个保留计数为1且具有方法接收者内容的新对象) retain
(此方法会将保留计数增加为1) 系统dealloc
自动执行保留计数为零的对象。完成后,您必须release
您拥有的每个对象。如果你release
太快,你会遇到危险的情况。如果你完成它后没有release
你的对象,你就会泄漏。
指针是一个特殊对象,它引用内存中的某个对象。它基本上是一个内存地址(和一些其他数据)。如果要使用对象,则必须alloc
为其存储内存,然后init
ialize。您(通过使用=
符号)指定指针。
string = [[NSString alloc] init];
string
现在有一个保留计数。但由于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 Runtime直接将这些数据类型与其值相关联,而不是指针。
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的app中)时,当事件循环结束当前循环时它将是release
d(当处理某个事件时它结束)。在Apple的文档中阅读有关Autorelease Pools的更多信息。
我希望我帮助那些不了解指针的人。在我进行大量实验之前,我自己有几个月的问题。 : - )