我有以下代码
NSArray *myArray = [[NSArray alloc] initWithObjects:@"1",@"2",nil];
NSMutableDictionary *dic0 = [[NSMutableDictionary alloc] initWithObjectsAndKeys:@"parag", @"name", myArray, @"arraye",nil];
NSMutableDictionary *dic1 = [[NSMutableDictionary alloc] initWithObjectsAndKeys:@"parag1", @"name", myArray, @"arrayr",nil];
NSMutableDictionary *dic2 = [[NSMutableDictionary alloc] initWithObjectsAndKeys:@"parag2", @"name", myArray, @"arrayq",nil];
NSMutableDictionary *dic3 = [[NSMutableDictionary alloc] initWithObjectsAndKeys:@"parag2", @"name", myArray, @"arrayqe",nil];
NSArray *array12424 = [[NSArray alloc] initWithObjects:dic0, dic1, dic2, dic3];
NSLog(@"array12424 %d", [array12424 retainCount]);
NSLog(@"array12424 %@", array12424);
int j = [myArray retainCount];
for(int i=0;i<j; ++i)
{
[myArray release];
NSLog(@"%d", i);
NSLog(@"myArray %@", myArray);
}
NSLog(@"array12424 %@", array12424);
释放myArray后,我预计会崩溃;为什么arraye和其他数组键指向array12424?
//output
2012-02-02 12:33:58.454 212121212[6924:a0f] array12424 1
2012-02-02 12:33:58.459 212121212[6924:a0f] array12424 (
{
arraye = (
1,
2
);
name = parag;
},
{
arrayr = (
1,
2
);
name = parag1;
},
{
arrayq = (
1,
2
);
name = parag2;
},
{
arrayqe = (
1,
2
);
name = parag2;
}
)
2012-02-02 12:33:58.459 212121212[6924:a0f] 0
2012-02-02 12:33:58.460 212121212[6924:a0f] myArray (
1,
2
)
2012-02-02 12:33:58.460 212121212[6924:a0f] 1
2012-02-02 12:33:58.460 212121212[6924:a0f] myArray (
1,
2
)
2012-02-02 12:33:58.461 212121212[6924:a0f] 2
2012-02-02 12:33:58.462 212121212[6924:a0f] myArray (
1,
2
)
2012-02-02 12:33:58.463 212121212[6924:a0f] 3
2012-02-02 12:33:58.463 212121212[6924:a0f] myArray (
1,
2
)
2012-02-02 12:33:58.464 212121212[6924:a0f] 4
2012-02-02 12:33:58.466 212121212[6924:a0f] myArray myArray
2012-02-02 12:33:58.466 212121212[6924:a0f] array12424 (
{
arraye = "array12424 ";
name = parag;
},
{
arrayr = "array12424 ";
name = parag1;
},
{
arrayq = "array12424 ";
name = parag2;
},
{
arrayqe = "array12424 ";
name = parag2;
}
)
我使用的是MAC osx 10.6 base SDK。
答案 0 :(得分:4)
0)不要使用retainCount
。
1)Cocoa Collections保留其内容,然后在删除时释放它们,或者当集合被销毁时释放它们。此外,没有明确说明您调用的API的文档不会自动发布其参数。
2)您没有正确初始化数组 - 必须终止为止:NSArray *array12424 = [[NSArray alloc] initWithObjects:dic0, dic1, dic2, dic3];
3)简单地说,没关系 - 它是未定义的行为。结果无法预测(除非涉及猛禽)。它在其他操作系统版本中崩溃。它会像你期望的那样在启用GuardMalloc时崩溃。之后不久就会崩溃(如果你很幸运的话)。
答案 1 :(得分:1)
拿2,让我们带您了解更详细的代码。首先,我们需要修复3个警告,并加强日志记录:
+ (void) test
{
NSArray *myArray = [[NSArray alloc] initWithObjects:@"1",@"2",nil];
NSMutableDictionary *dic0 = [[NSMutableDictionary alloc] initWithObjectsAndKeys:@"parag", @"name", myArray, @"arraye",nil];
NSMutableDictionary *dic1 = [[NSMutableDictionary alloc] initWithObjectsAndKeys:@"parag1", @"name", myArray, @"arrayr",nil];
NSMutableDictionary *dic2 = [[NSMutableDictionary alloc] initWithObjectsAndKeys:@"parag2", @"name", myArray, @"arrayq",nil];
NSMutableDictionary *dic3 = [[NSMutableDictionary alloc] initWithObjectsAndKeys:@"parag2", @"name", myArray, @"arrayqe",nil];
NSArray *array12424 = [[NSArray alloc] initWithObjects:dic0, dic1, dic2, dic3, nil];
NSLog(@"array12424 %lu", [array12424 retainCount]);
NSLog(@"array12424 %p, %@", array12424, array12424);
NSUInteger j = [myArray retainCount];
for(NSUInteger i=0;i<j; ++i)
{
NSLog(@"%lu, %lx", i, [myArray retainCount]);
[myArray release];
NSLog(@"%lu, %lx", i, [myArray retainCount]);
NSLog(@"myArray %p, %@", myArray, myArray); // breakpoint here
}
NSLog(@"array12424 %p, %@", array12424, array12424);
}
在指定的行上放置一个断点并调用该方法。
当你第一次在控制台上看到以下内容时点击断点:
2012-02-03 07:36:34.651 sandpit[32581:903] array12424 1
2012-02-03 07:36:34.659 sandpit[32581:903] array12424 0x100176820, (
{
arraye = (
1,
2
);
name = parag;
},
{
arrayr = (
1,
2
);
name = parag1;
},
{
arrayq = (
1,
2
);
name = parag2;
},
{
arrayqe = (
1,
2
);
name = parag2;
}
)
2012-02-03 07:36:34.660 sandpit[32581:903] 0, 5
2012-02-03 07:36:34.661 sandpit[32581:903] 0, 4
首先看一下最后一行,我们看到保留计数是5.现在我们创建并拥有了数组 - 这是1 - 我们已经将它添加到4个字典中并且它们保留了它们的参数 - 这是另外4个。这5个中的任何一个实际上是否会产生误导,是否会有一个待定的autorelease
或两个会使它掉线?在这种情况下,我们可以确定不是因为我们没有自动释放,并且集合保留了它们的参数。
在调试器变量显示中,查看myArray
myArray = (NSCFArray *) 0x100513aa0 2 objects
这告诉我们引用我的myArray
的Obj-C对象确实是一个数组,它位于内存地址0x100513aa0
并包含两个项目。您将在控制台中看到该地址,因为将'%p'添加到某些NSLog中。
现在按几次继续,直到最后一个控制台输出为:
2012-02-03 07:37:33.074 sandpit[32581:903] 4, 1
2012-02-03 07:37:33.074 sandpit[32581:903] 4, fffffffffffffff
现在您可以看到为什么我使用`%lx'来打印保留计数而不是匹配其类型的'%lu'(无符号64位整数)。保留计数显然消极了!
真正发生的事情是前一个release
将计数发送到0然后内存可以重新使用 - 所有这些NSLog都是格式化字符串并需要内存,所以有一些流失。
现在查看调试器中的myArray
条目 - 它是否仍然说它是一个包含2个对象的数组?可能不是。我用各种伪装运行这个代码,它认为它是一个空数组,一个带有2个空值的数组,一个字符串......你在问题中看到了什么 - NSLog输出中的字符串......它指向释放内存,它可以包含任何内容。
Obj-C中存在 NO 内存安全性,您可以根据需要随意读写内存。不能保证像过度释放内存那样会导致立即崩溃,或者确实发生任何崩溃,但应用程序很可能会以某种方式出现故障。
HTH。
如果你想深入挖掘,你可以编写自己的代码来打印显示所包含对象的地址(使用'%p')的字典,或者只是深入调试器中的字典,这样你就可以看到共享
强制性健康警告:retainCount
在学习时非常有用,但永远不会,在实际代码中使用它确定是否需要release
d,因为可能存在您不知道的待定减量(来自autorelease
)。
答案 2 :(得分:0)
首先在此声明中添加nil
NSArray *array12424 = [[NSArray alloc] initWithObjects:dic0, dic1, dic2, dic3,nil];
现在遇到崩溃只需更改此代码
for(int i=0;i<j; ++i)
{
[myArray release];
NSLog(@"%d", i);
NSLog(@"let the system remove this array, give him some time dude to remove it, then see what happens");
NSLog(@"myArray %@", myArray);
}
答案 3 :(得分:-1)
我假设这个问题是要了解可可内部工作......
保留计数0并不意味着对象被删除...在保留计数达到0之后,cocoa内部有自己的逻辑来调用对象上的dealloc。
你可以尝试在不同的事件上下文中调用last语句...通常在事件上下文之后使用对象。
答案 4 :(得分:-1)
我的猜测是你正试图了解内存分配&amp;解除分配,这不是您打算在实际应用程序中放置的代码。
在这种情况下,尝试使用%p
格式打印对象引用进行探索 - 这将打印对象的地址。然后,您将能够看到哪些对象真正被共享(而不仅仅是具有相同的内容)以及何时重用内存等。或者使用调试器为您提供相同的功能。
在探索时,可以放弃避免retainCount
的一般建议。