这与我的其他问题here
基本相关我正在尝试发布包含viewControllers的NSMutableArray
。我这样做:
self.viewControllers = nil;
在viewWillDisappear
,因为我正在转向另一种观点。但无论我做什么,视图控制器都不会被释放。我也尝试过:
[[scrollView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
其中scrollview是拥有包含NSMutableArray
的视图。
虽然包含NSMutableArray
的引用计数为0,但我看到实时视图控制器(在乐器中)的数量没有变化。
答案 0 :(得分:2)
有几点意见:
确保通过静态分析器运行非ARC代码。这可以找到许多困扰非ARC代码的内存管理问题。从Xcode的“产品”菜单中选择“分析”,或按命令 + shift + B 。如果您使用ARC,很多这些内存管理问题都会消失,但如果您不使用ARC,静态分析器在检查代码时非常有用。
您对removeFromSuperview
的尝试是不必要的,并且不会影响视图控制器的retainCount
本身。但是,我是否从这种尝试推断出您已经创建了视图控制器,然后将它们的视图添加到滚动视图中?如果是这样,你是否为每个人做了必要的addChildViewController
?如果是这样,您确实需要为每个人执行相关的removeFromParentViewController
。
视图控制器的正确释放取决于您如何定义和分配viewControllers
数组,以及如何填充它。
但是,例如,我有一个属性:
@property (nonatomic, retain) NSMutableArray *array;
我用以下代码初始化它(请注意autorelease
本身的NSMutableArray
(因为我正在使用将为我保留的访问器方法),以及显式{{1 } release
个对象):
Object
如果我检查了- (void)makeArray
{
// create an array, using the accessor method (thus why I'm using an autorelease object)
self.array = [[[NSMutableArray alloc] init] autorelease];
// just add four random objects to the array.
// note, adding them to the array increases their retain count, thus I
// release them to bring the retain count back to +1 ... I could have
// done that via autorelease, too
for (NSInteger i = 1; i < 4; i++)
{
Object *obj = [[Object alloc] initWithString:[NSString stringWithFormat:@"Test %d", i]];
[self.array addObject:obj];
[obj release];
}
}
值,我可以看到所有内容都有retainCount
+1,这是合适的:
retainCount
当我在以下方法中清除它时,它(以及数组的各个对象)被正确释放(事实证明- (void)logArray
{
// let's examine the retain counts for the objects in the array
// should be "1" given there are no other strong references anywhere
for (id obj in self.array)
NSLog(@"%s %@ (retainCount = %d)", __FUNCTION__, obj, [obj retainCount]);
// let's also examine the retain count for the array, itself
// this should also be "1"
NSLog(@"%s retainCount = %d", __FUNCTION__, [self.array retainCount]);
}
类在其Object
期间NSLog
dealloc
方法):
- (void)clearArray
{
// let's use the accessor method to release the array and make sure
// the pointer is nil
self.array = nil;
}
这是一种冗长的说法,即self.viewControllers = nil;
的语法是一种非常适合释放数组(以及它的成员对象)的方法,假设数组被定义为{ {1}}属性,如上一点所示。但是,如果数组的成员对象没有被释放,那么这些对象显然没有将retain
降为零。我会在retainCount
之前尝试,不仅记录数组本身的self.viewControllers = nil;
,还记录数组中各个对象的retainCount
,以确认它们retainCount
}设置。
他们在那时应该都有+1 retainCount
(否则还有其他东西保留它们,要么因为它们被过度保留,要么有一些保留周期(又称强参考周期)那些视图控制器或其他东西合法地保留它们(例如,在某些时候你将其中一个视图控制器推到导航器堆栈上,但你还没有将它们弹出))。
如果你还在泄漏,我会使用乐器来find the leak。顺便说一下,当检查调用树是否泄漏时,我发现它对“反转调用树”和“隐藏系统库”很有用。
<强>更新强>
上面,在第4点,我警告保留周期的风险。保留周期的一个示例是视图控制器使用retainCount
,并且在释放视图控制器时失败到NSTimer
和invalidate
计时器。离线与您聊天,听起来这可能就是问题,您尝试release
release
NSTimer
,dealloc
永远不会调用,因为计时器,本身,保留视图控制器。在释放dealloc
之前,您需要为具有计时器的任何视图控制器手动invalidate
和release
NSTimer
(通过释放对视图控制器的强引用)。 (例如,可能有一个停止计时器的协议,让你的孩子视图控制器符合那个。)
答案 1 :(得分:1)
一旦掌握了这些工具,隔离此类问题所需的时间(通常)应缩短为几分钟。
答案 2 :(得分:0)
你可以做一个快速测试:
- (void) test
{
NSMutableArray *testArray = [NSMutableArray arrayWithCapacity:0];
// MyViewController is your view controller class
MyViewController *vc = [[MyViewController alloc] initWithNibName:@"MyViewController" bundle:nil]; // add autorelease if you aren't using ARC
[testArray addObject:vc];
// On exit, testArray will be released, so will vc
}
在MyViewController中的dealloc上设置断点并检查它是否被调用。如果它被调用,而不是在你的代码中,则意味着你的视图控制器被保留在某个地方,你必须找到它们保留的位置。