Как правильно разблокировать и переключать представления в мультивьювном контроллере? - PullRequest
1 голос
/ 15 марта 2009

Я пытаюсь создать контроллер многооконного просмотра для игры, в которой один контроллер корневого представления освобождает представления перед переключением на другое представление. Контроллеры подчиненного представления, в свою очередь, сами являются подчиненными контроллерами представления, поскольку они содержат другие контроллеры представления.

Например, мой singlePlayerViewController будет иметь shakeObjectViewController и, возможно, другие. При использовании листов действий для переключения между представлениями с делегатом приложения в качестве делегата действий все работает, как и ожидалось, при переходе от представления singlePlayer к другому.

Но когда я пытаюсь создать новый singlePlayerViewController, используя те же методы init, отладчик выдает ошибку 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 не вставляет подпредставления, а вместо этого заменяет свое собственное представление на представление контроллера подвида. (Не знаю, если это хорошая практика или нет:?:)

При переключении представлений делегат приложения выполняет следующее:

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

[rootViewController initMultiplayerView];

Затем при переключении обратно в однопользовательский режим выполняется тот же метод init в viewDidLoad rootViewController.m, и отладчик выдает ошибку в «[self.view insertSubview: singlePlayerViewController.view atIndex: 0];» линия.

Есть идеи, почему не создается новый вид? Я попытался установить для singlePlayerViewController значение nil вместо освобождения, но затем выдается сообщение об ошибке "self.view = shakeController.view;" линия. Насколько я понимаю, если свойство view в настоящее время равно nil, то при следующем доступе к нему автоматически создается новое.

initWithNibName должен выполняться только один раз? Или мой дизайн слишком запутан с точки зрения контроллеров представления?

Ответы [ 4 ]

2 голосов
/ 30 марта 2009

Обратите внимание, что мой singlePlayerViewController не вставляет подпредставления, а вместо этого заменяет свое собственное представление на представление контроллера подвида. (Не знаю, если это хорошая практика или нет:?:)

Огромный флаг предупреждения здесь. Похоже, у вас есть одно представление с двумя контроллерами представления. Это плохо.

Попробуйте вместо этого вставить и удалить подпредставления:

  • RootView
    • SinglePlayerView (может быть удален и заменен на MutliplayerView)
      • ShakeView

Таким образом, у вас есть 3 вида с 3 контроллерами вида.

Это способ использования фреймворка.

0 голосов
/ 14 июля 2010

То, как вы это сделали, меня очень смущает, и я думаю, что ответственно за вашу ошибку. Я прохожу это построчно и пытаюсь выяснить, почему он падает, и не совсем понимаю, но в то же время мне трудно понять, что происходит с представлениями во время переключения.

Я бы переписал это, как предлагает Кайлоа, с тремя разными контроллерами представления. У каждого представления должен быть свой контроллер. Представление не должно заменять себя, оно должно быть заменено контроллером суперпредставления.

Я подозреваю, что где-то в ней что-то высвобождается, а затем обменивается сообщениями, и затем вы пытаетесь что-то сделать с возвратом этого сообщения, думая, что что-то является объектом, когда это не так.

0 голосов
/ 16 марта 2009

Да, все операторы @property помечены (неатомные, сохраняют).

Может быть, вопрос можно переформулировать так: как вы создаете контроллер представления из пера несколько раз? Во второй раз, когда я создаю VC, независимо от освобождения предыдущего VC того же класса, связанный вид не создается и выдает ошибку BAD ACCESS.

0 голосов
/ 15 марта 2009

Ваш дизайн кажется слишком сложным, но это не значит, что отладчик должен выдавать случайные ошибки! :) Попытка упростить это может помочь, хотя. Я не понимаю, зачем вам нужен вид с одним игроком, если вы просто собираетесь немедленно заменить его на объект встряхивания.

Я определенно думаю, что вы хотите установить для singlePlayerViewController значение nil, поскольку в противном случае строка «if (singlePlayerViewController == nil) {» в методе viewViewidLoad rootViewControllers будет ложной, и новый контроллер представления не будет создан, поэтому Вы получаете эту первую ошибку.

Я вижу только 3 способа получения ошибки доступа в строке "self.view = shakeController.view":

  • shakeController не ноль, но мусор. Это кажется маловероятным, поскольку он был только инициирован, если его viewDidLoad не выпускает сам себя или что-то в этом роде.
  • Я не ноль, но мусор. Опять же, маловероятно, но возможно - возможно, проверьте в отладчике, чтобы посмотреть, как выглядит self (имеют ли смысл его переменные и т. Д.)
  • когда вы вызываете self.view = ..., он отправит релиз в исходный вид. Есть ли какой-нибудь код в методе dealloc вида одиночного игрока, который может вызвать ошибку доступа?

Если значение self или shakeController равно nil, ошибка не будет, потому что строка эквивалентна

[self setView:[shakeController view]]

который не вылетел бы, если бы они были равны нулю, поскольку сообщения на ноль разрешены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...