如何在多视图控制器中正确释放和切换视图?

时间:2009-03-15 15:51:05

标签: iphone cocoa-touch

我正在尝试为游戏创建一个多视图控制器,其中一个根视图控制器在切换到另一个视图之前释放视图。子视图控制器又是子视图控制器本身,因为它们包含其他视图控制器。

例如,我的s​​inglePlayerViewController将有一个shakeObjectViewController,可能还有其他人。使用操作表在视图之间切换,将app delegate作为操作表的委托,从singlePlayer视图转到另一个视图时,一切都按预期工作。

但是当我尝试使用相同的init方法创建一个新的singlePlayerViewController时,当我尝试插入子视图时,调试器会抛出一个EXC _BAD _ ACCESS错误,即shakeObjectViewController.view。

此时初始化看起来像这样: 应用程序委托使用默认的init方法

初始化窗口
- (void)applicationDidFinishLaunching:(UIApplication *)application {   
    // Override point for customization after application launch
   [window addSubview:rootViewController.view];
    [window makeKeyAndVisible];
}

然后在rootViewController.m的viewDidLoad中,

   if(singlePlayerViewController == nil) {

      SinglePlayerViewController *singleController = [[SinglePlayerViewController alloc]
                                       initWithNibName:@"SinglePlayerView" bundle:nil];
      self.singlePlayerViewController = singleController;
      [singleController release];
   }

   [self.view insertSubview:singlePlayerViewController.view atIndex:0];

后面是singlePlayerViewController.m,

- (void)viewDidLoad {
   self.view.tag = kSinglePlayerView; // tag the view

   ShakeObjectViewController *shakeController = [[ShakeObjectViewController alloc]
                                       initWithNibName:@"ShakeObjectView" bundle:nil];
   self.shakeObjectViewController = shakeController;
   self.view = shakeController.view;
   [shakeController release];
}

注意我的singlePlayerViewController不是插入子视图,而是用子视图控制器的视图替换它自己的视图。 (不知道这是不是一个好习惯:?:)

切换视图时,app委托执行以下操作:

for(UIView *subview in [rootViewController.view subviews])
{   
   [subview removeFromSuperview];
}
[rootViewController.singlePlayerViewController release]

[rootViewController initMultiplayerView];

然后当切换回单一播放器模式时,执行rootViewController.m的viewDidLoad中的相同init方法,并且调试器会在“[self.view insertSubview:singlePlayerViewController.view atIndex:0]”上抛出错误;“线。

关于为什么没有创建新视图的任何想法?我已经尝试将singlePlayerViewController设置为nil而不是释放,但是然后在“self.view = shakeController.view”上抛出错误线。 我的理解是,如果view属性当前为nil,则在下次访问视图时会自动为您创建一个新属性。

initWithNibName只能执行一次吗?或者我的设计方式在#view controllers方面太复杂了?

4 个答案:

答案 0 :(得分:2)

  

注意我的singlePlayerViewController不是插入子视图,而是用子视图控制器的视图替换它自己的视图。 (不知道这是不是一个好习惯:?:)

这里有巨大的警告标志。听起来你有一个带有两个视图控制器的视图。这是不好的。

考虑插入和删除子视图:

  • RootView
    • SinglePlayerView(可以删除并替换为MutliplayerView)
      • ShakeView

这样你就有3个视图,有3个视图控制器。

这就是框架的使用方式。

答案 1 :(得分:0)

您的设计似乎有点过于复杂,但这并不意味着调试器应该抛出随机错误! :)尽管如此,试图简化它可能会有所帮助。如果您只是立即用摇动对象视图替换它,我不明白为什么您需要单个玩家视图。

我绝对认为你想将singlePlayerViewController设置为nil,因为否则rootViewControllers viewDidLoad方法中的行“if(singlePlayerViewController == nil){”将为false,并且不会创建新的视图控制器,这就是为什么你得到第一个错误。

我只看到3种方法可以在“self.view = shakeController.view”行上获得访问错误:

  • shakeController非零,但垃圾。这似乎不太可能,因为它只是初始化,除非它的viewDidLoad发布自己或类似的东西。
  • 自我不是零,而是垃圾。再一次,不太可能,但可能 - 可能在调试器中检查以查看自己的样子(其变量是否有意义等)。
  • 当你调用self.view = ...时,它会向原始视图发送一个版本。单个播放器视图的dealloc方法中是否存在可能导致访问错误的代码?

将self或shakeController设为nil不会导致错误,因为该行等同于

[self setView:[shakeController view]]

如果那些是零,则不会崩溃,因为允许消息为nil。

答案 2 :(得分:0)

是的,所有@property语句都标有(非原子,保留)。

也许这个问题可以重申,你如何不止一次从笔尖创建一个视图控制器?第二次创建VC时,无论是否释放同一类的前一个VC,都不会创建关联的视图,并且会抛出BAD ACCESS错误。

答案 3 :(得分:0)

你这样做的方式对我来说非常混乱,我认为对你的错误负责。我会逐行检查它并试图弄清楚它为什么会崩溃并且没有把它搞清楚,但与此同时我很难弄清楚切换期间视图发生了什么。

我会改写这个,因为Kailoa建议使用三个不同的视图控制器。每个视图都应该有自己的控制器。视图不应替换自身,应由超级视图控制器替换。

我怀疑她身上的某个地方正在被释放然后发出消息,然后你尝试对该消息的返回做一些事情,认为某事物是不是的对象。

相关问题