Ios 容器UIViewController未释放它';s子视图控制器
我有一个自定义容器UIViewController,它有六个子UIViewController,还有一组选项卡,用户可以与这些选项卡交互以在子视图控制器之间切换。问题是当我的容器视图控制器被释放时,子视图控制器没有被释放 我已经通过向dealloc方法添加一些调试代码验证了子视图控制器没有被释放,并且只要它们的视图没有被添加到容器视图控制器的视图中,它们就会被释放 下面是我用来创建自定义容器视图控制器的代码摘录。viewController指针是IVAR。我也在使用ARC,这就是为什么没有实际的释放调用Ios 容器UIViewController未释放它';s子视图控制器,ios,uiviewcontroller,automatic-ref-counting,Ios,Uiviewcontroller,Automatic Ref Counting,我有一个自定义容器UIViewController,它有六个子UIViewController,还有一组选项卡,用户可以与这些选项卡交互以在子视图控制器之间切换。问题是当我的容器视图控制器被释放时,子视图控制器没有被释放 我已经通过向dealloc方法添加一些调试代码验证了子视图控制器没有被释放,并且只要它们的视图没有被添加到容器视图控制器的视图中,它们就会被释放 下面是我用来创建自定义容器视图控制器的代码摘录。viewController指针是IVAR。我也在使用ARC,这就是为什么没有实际的
- (void)init
{
if ((self = [super init])) {
vc1 = [[UIViewController alloc] init];
[self addChildViewController:vc1];
vc2 = [[UIViewController alloc] init];
[self addChildViewController:vc2];
vc3 = [[UIViewController alloc] init];
[self addChildViewController:vc3];
vc4 = [[UIViewController alloc] init];
[self addChildViewController:vc4];
vc5 = [[UIViewController alloc] init];
[self addChildViewController:vc5];
vc6 = [[UIViewController alloc] init];
[self addChildViewController:vc6];
}
return self;
}
- (void)dealloc
{
[vc1 removeFromParentViewController];
vc1 = nil;
[vc2 removeFromParentViewController];
vc2 = nil;
[vc3 removeFromParentViewController];
vc3 = nil;
[vc4 removeFromParentViewController];
vc4 = nil;
[vc5 removeFromParentViewController];
vc5 = nil;
[vc6 removeFromParentViewController];
vc6 = nil;
}
- (void)switchFromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController
{
if (fromViewController) {
[fromViewController.view removeFromSuperview];
}
[self.view addSubview:toViewController];
toViewController.view.frame = self.view.bounds;
}
你们知道我做错了什么吗?这不是添加和删除子视图控制器的方法
[childViewController willMoveToParentViewController:nil];
[childViewController view] removeFromSuperview];
[childViewController removeFromParentViewController];
删除和添加的方法是什么
[parentViewController addChildViewController:childViewController];
[parentViewController.view addSubview:childViewController.view];
[childViewController didMoveToParentViewController:parentViewController];
正如我所怀疑的,问题与问题中的视图控制器包含代码无关,而是您添加了观察者(您在回答此问题时讨论了这一点): 你试图用它来移除它
[[NSNotificationCenter defaultCenter] removeObserver:self name:kUpdateEventName object:nil];
因此,有两个问题:
addObserverForName:object:queue:
,则这不是删除此观察者的正确方法。相反,请定义一个属性来跟踪观察者:
@property (nonatomic, weak) id<NSObject> notification;
如果要删除它,请使用以下引用:
[[NSNotificationCenter defaultCenter] removeObserver:self.notification];
这将确保观察员将被适当撤职addObserverForName:object:queue:
的此块必须引用self
。如果您试图在dealloc
中正确删除此观察者(如上所示),您仍然会有一个强引用周期(以前称为保留周期)。这可以通过多种方式解决,但最可靠的模式是首先通过使用weakSelf
模式来防止强引用循环:
typeof(self) __weak weakSelf = self;
self.notification = [[NSNotificationCenter defaultCenter] addObserverForName:kFooNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
// use `weakSelf` in this block; not `self`
}];
我原来的答覆如下:
虽然Srikanth是正确的,在
addChildViewController
之后,您应该调用didMoveToParentViewController:self
,在从ParentViewController移除之前,您应该调用willMoveToParentViewController:nil
。但那不是你的问题。事实上,我使用了您代码的一个变体(即使没有dealloc
),子控制器也可以很好地发布
总之,我怀疑你的问题在其他地方,可能是某个地方的一个保留周期。例如,您的孩子是否对家长有强烈的引用?你在使用循环计时器吗?您引用了一些选项卡。您没有使用选项卡栏控制器,是吗?一定是这样的
[如果您想查看原始答案的其余部分以及OP代码示例中的代码片段和次要细节,请参阅修订历史记录]经过数小时的努力,我终于找到了导致我的子视图控制器无法正确释放的原因
每个视图控制器中都声明了以下通知,以便它们能够响应各种事件
[[NSNotificationCenter defaultCenter] addObserverForName:UPDATE_EVENT object:nil queue:nil usingBlock:^(NSNotification *note) {
// do stuff when update happen
}];
结果是由于某种原因,我的视图控制器无法正确释放。我猜这会将视图控制器添加到NSNotificationCenter观察者列表中,并且在我执行以下操作时没有被删除
[[NSNotificationCenter defaultCenter] removeObserver:self name:UPDATE_EVENT object:nil];
因此,为了解决我的问题,我只是将通知更改为注册,如下所示
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateEvent:) name:UPDATE_EVENT object:nil];
我不知道为什么我注册通知的方式不允许我的视图控制器正确释放,但这似乎已经修复了它。如果有人对为什么会发生这个问题有任何见解,请让我知道
谢谢 出于好奇,您引用了控制显示哪个子级的选项卡。你是如何实现的?我问这个问题是因为我看到您将孩子的frame
设置为self.view.frame
,所以我不知道您会在家长视图的何处显示此选项卡控件。这只是我实际代码正在执行的一个超快速示例,所以没有100%仔细考虑。在我的实际应用程序中,有一些选项卡沿侧面垂直运行,然后在主视图控制器中有一个视图,子视图控制器视图被放入其中,然后它们的框架被设置为childViewController.frame=contentContainerView.bounds;这是有道理的。乍一看,看到一个占据整个屏幕的遏制示例,我不禁怀疑是否需要遏制。不过,听起来你的计划不错。对不起打扰你了谢谢你的信息员。是的,在你提到我发布的原始代码正在释放孩子们之后,我决定尝试将我的孩子视图控制器类切换到一个新的子类,这个子类除了在Dealoc期间注销标题之外什么都不做。就像你做的一样。完成后,子视图控制器开始正确释放。所以我想我在其他地方有问题。再次感谢你的帮助!我认为,附加到观测者的“更新发生时做事情”块正在关闭对“self”的非块安全引用,并泄漏该引用[
[[NSNotificationCenter defaultCenter] removeObserver:self name:UPDATE_EVENT object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateEvent:) name:UPDATE_EVENT object:nil];