添加子视图通知未收到

3
我面临一个奇怪的问题... 我想将一个名为iView的UIView控制器添加到我的当前视图中。 我通过调用下列代码来实现:
   iView = [[KFKaraokeInfosView alloc] initWithKaraoke:karaoke NibName:@"InfosView" commingFromPlayer:NO];
    iView.songTitle.text = karaoke.title;
    [self.view addSubview:iView.view];

在iView的viewDidLoad中,我将其添加为NotificationCenter的观察者以接收特定通知,代码如下:
    - (void)viewDidLoad
    {
        [super viewDidLoad];

        self.title = @"About";

        if ([karaoke.styles count] == 0)
        {
            [[NSNotificationCenter defaultCenter] postNotificationName:@"GetInfosOfSong" object:self.karaoke];
        }
        else
        {
            shouldSetup = YES;
        }

        [self.navigationController setNavigationBarHidden:NO animated:YES];
        [self.navigationController.navigationBar setBarStyle:UIBarStyleBlack];

        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(setup) name:GetSongInfos  object:nil];
        [optionsTableView setBackgroundView:nil];

    }

问题在于当我在初始化时对iView调用autorelease方法时,通知永远不会被捕获(因此setup方法从未被调用),但是如果我不对iView调用autorelease,则可以正常工作。
我不理解这种情况下的内存管理,有人能帮助我理解吗?

1
你能描述一下你想做什么吗?是在视图控制器容器中添加一个子视图?还是转换到新视图?你能分享一下代表你正在使用控制器的代码吗?在视图控制器之间进行转换时,不应该使用 addSubview,而在进行视图控制器容器(即使这个新控制器成为当前控制器所表示屏幕的一部分)时,应该使用 addChildViewController 和相关的容器调用。总之,答案取决于你想要做什么。 - Rob
你能否在添加通知观察者的位置添加你的代码? - SpaceDust__
我正在尝试在视图控制器容器中添加一个子视图,通过像弹出窗口一样显示新视图,我刚刚编辑了我的问题。 - Matthias
你能展示一下你在哪里使用了 addChildViewControllerdidMoveToParentViewController 等代码吗? - Rob
你是否处于ARC环境中? - tiguero
不,我不在 ARC 环境中。 - Matthias
1个回答

0

容器视图控制器方法可以在UIViewController类参考实现容器视图控制器中找到,示例代码可以在视图控制器编程指南创建自定义容器视图控制器中找到。

因此,在iOS 5及更高版本中,您应该有:

iView = [[[KFKaraokeInfosView alloc] initWithKaraoke:karaoke NibName:@"InfosView" commingFromPlayer:NO] autorelease];
[self addChildViewController:iView];
iView.songTitle.text = karaoke.title;
[self.view addSubview:iView.view];
[iView didMoveToParentViewController:self];

如果是iOS 4或更早版本,则不支持适当的包含。您可以手动添加视图,就像您正在做的那样,而没有使用autorelease来进行修补。
iView = [[KFKaraokeInfosView alloc] initWithKaraoke:karaoke NibName:@"InfosView" commingFromPlayer:NO];
iView.songTitle.text = karaoke.title;
[self.view addSubview:iView.view];

你显然会在父视图控制器的某个ivar中保留子视图控制器的副本,而不是将其autorelease,而是在子视图被解除时明确地release子控制器。请注意,由于您正在使用iOS4之前的版本,因此不能保证您的子控制器会收到各种事件(尤其是旋转事件)。但是您应该能够接收到通知中心事件。

避免在iOS 4中尝试伪造容器的另一种方法是根本不使用子视图控制器,而只是将子视图添加到父视图中。实际上,您可以将其添加到父控制器的NIB中,但只需隐藏它。然后,当您想要呈现它时,取消隐藏即可。但是保持所有内容都在父视图控制器及其NIB中。我上面描述的伪装容器的方法可能有效(我见过人们这样做),但它让我感到毛骨悚然。这更简单。


我需要支持IOS 4.3,这个版本支持addChildViewController方法吗? - Matthias
2
啊,不行。在iOS 5之前是不支持容器的。如果你试图为子视图创建控制器,那在iOS 4中会变得混乱不堪。 - Rob
@Matthias 啊,不是的。你的问题在于如果你使用autorelease,你的控制器会被丢弃,即使它的视图仍然在屏幕上。所以你真的需要在父视图控制器的某个ivar中保留子视图控制器的副本,而不是将其autorelease,但在子视图关闭时明确地release控制器。但由于你正在一个预先包含iOS4的世界中操作,你的子控制器不能保证接收到各种事件(尤其是旋转事件)。 - Rob
我理解你的想法。只是我认为每次将子视图添加到父视图后,都需要立即释放它(就像推送一个UIViewController时一样)。 - Matthias
1
不,当你使用pushViewController时,它会为你保留,因此你可以安全地使用autorelease。而当你进行适当的容纳时,addChildViewController也会为你保留它。但在这种情况下,你没有任何东西可以为你保留它,所以你必须自己手动清理并接受各种视图控制器事件将永远无法到达你的子控制器的事实。但你应该能够接收到你的通知中心事件。 - Rob
好的,我就这样做!非常感谢你的帮助@Rob! - Matthias

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接