Предупреждение: -Представление контроллеров представления на контроллерах отдельного представления не рекомендуется

180

В моем приложении я использую навигационный контроллер. Позже в некотором представлении я использую presentViewControllerдля показа увеличенного изображения. Также я не использую раскадровку или перо.

Я получаю эту ошибку только в iOS 7. Он отлично работает в iOS 6 и более ранних версиях:

Представление контроллеров представления на независимых контроллерах представления не рекомендуется

Гаган Джоши
источник
Я еще не понял. Но в моем приложении я не назначаю никакой viewcontroller для window.rootviewcontroller. Я добавляю вид в окно. Может быть, это причина для меня. но не уверен ...
Гаган Джоши
@GaganJoshi Причина, которую вы упомянули выше, может не быть причиной. Даже я сталкиваюсь с той же проблемой. И в нашем проекте я назначаю контроллер представления для window.rootviewcontroller.
Раджеш
1
Я думаю, что другие комментарии правильно связывают это с чем-то о rootViewController и оконном соединении. Я не совсем понял это, но я смог обойти эту проблему, представив контроллер непосредственно на rootViewController, а не на навигационном контроллере или одном из его дочерних элементов.
Рич Уотерс
Azaxis получил его: stackoverflow.com/a/31877722/5306470
Даниэль Спрингер

Ответы:

207

Чтобы избежать получения предупреждения в push-навигации, вы можете напрямую использовать:

[self.view.window.rootViewController presentViewController:viewController animated:YES completion:nil];

И затем в вашем контроллере модального представления, когда все закончится, вы можете просто позвонить:

[self dismissViewControllerAnimated:YES completion:nil];

cdescours
источник
Я представляю средство выбора изображения с этим кодом строки "[self.view.window.rootViewController presentViewController: viewController animated: YES завершение: nil];" Но невозможно отклонить представление с помощью этой строки "[self dismissViewControllerAnimated: YES завершение: nil];" Любой альтернативный вариант для dismisscontroller
kb920
@keyurbhalodiya Вам нужно вызвать метод dismissViewController из modalView, чтобы он заработал. Поэтому, если вы отображаете представление с именем viewB из viewA с помощью [viewA.window.rootViewController presentViewController: viewB], в viewB вам нужно добавить кнопку, например, связанную с пользовательским действием, вызывающим [self dismissViewControllerAnimated]. Это понятнее?
cdescours
11
Не представляет viewcontroller в iOS 8.
Раджеш Маурья
1
для iOS 8: [self.view.window.rootViewController.navigationController
Fede Cugliandolo,
31
используя self.navigationControllerсделал это для меня.
Брэндон Захари
62

Причина этого предупреждения в том, что я представлял контроллер представления поверх небольшого представления, которое не является полноразмерным представлением. Ниже приведено изображение моего проекта. где при нажатии на четыре варианта выше. Пользователь переходит к другому представлению childviewcontroller (работает как tabViewcontroller). Но childviewcontroller содержит представление небольшого размера. Поэтому, если мы представляем представление childviewcontroller, оно выдает это предупреждение.

основной вид детали

И чтобы избежать этого, вы можете представить представление о родителе childviewcontroller

  [self.parentViewController presentViewController:viewController animated:YES completion:nil];
Гаган Джоши
источник
1
[self.view.window.rootViewController.navigationController pushViewController: YOUR_VIEW_CONTROLER animated: YES];
Феда Кульяндоло
1
msgstr "представлял контроллер представления поверх небольшого представления, которое не является полноразмерным представлением." ... ИМЕННО. Хорошая работа.
Толстяк
61

Ждите viewDidAppear():

Эта ошибка также может возникнуть, если вы пытаетесь представить контроллер представления до того, как представление действительно появилось, например, представление представления в viewWillAppear()или ранее. Попробуйте представить другой вид после viewDidAppear()или внутри него.

Azaxis
источник
9
Другими словами, не представляйте никаких контроллеров представления viewDidLoad(), люди! Я делал эту ошибку очень много раз ...
T Blank
Спасибо, это помогло. У меня был код в viewDidLoad, где он пытался отобразить диалог в конце.
ArdenDev
Я получаю эту ошибку при запуске модульных / интеграционных тестов, когда я не тестирую анимации.
mixtly87
21

В моем случае я sampleViewControllerдобавил представление в качестве подпредставления, а затем попытался представить поповер из представления sampleViewController(здесь selfвместо UIViewControllerэкземпляра):

[self.view addSubview:sampleViewController.view];

Правильный путь должен быть ниже:

// make sure the vc has been added as a child view controller as well
[self addChildViewController:sampleViewController];
[self.view addSubview:sampleViewController.view];
[sampleViewController didMoveToParentViewController:self];

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

Kjuly
источник
Кроме того, вызовите didMoveToParentViewController. Просьба проверить Установка и удаление ChildViewController: gist.github.com/tomohisa/2897676
Jakehao
@jianzong Я помню, что нет необходимости делать последний шаг. В любом случае, позвольте мне добавить это, спасибо за предложение. :)
Kjuly
Да, это будет работать без последнего шага. Я думаю, что цель этого - сообщить parentViewController, чтобы он вызывал некоторые методы, чтобы что-то сделать. :)
Jakehao
2
это работает для меня, я использую одно представление контроллеров в другом контроллере - (Представление контейнера программно), я не добавил [self addChildViewController:sampleViewController];, теперь я добавил это, спасибо
anjnkmr
16

Я думаю, что проблема в том, что у вас нет правильной иерархии контроллеров представления. Установите rootviewcontroller приложения и затем отображайте новые представления, выдвигая или представляя на них новые контроллеры представлений. Пусть каждый контроллер представления управляет своими представлениями. Только контроллеры представления контейнера, такие как tabbarviewcontroller, должны когда-либо добавлять другие представления контроллеров представления к своим собственным представлениям. Прочтите руководство по программированию контроллеров представления, чтобы узнать больше о том, как правильно использовать контроллеры представления. https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/

Даниэль Иттербринк
источник
14

Swift 3

Для тех, кто спотыкается об этом, вот быстрый ответ.

self.parent?.present(viewController, animated: true, completion: nil)
Жереми
источник
9

У меня почти такая же проблема. Причина была в том, что я пытался представить «некоторый» контроллер на другом, и после завершения анимации я устанавливал представленный контроллер как root. После этой операции все дальнейшие представления контроллеров приводят меня к предупреждению: « Представление контроллеров представления на контроллерах отдельного представления не рекомендуется ». И я решаю это предупреждение просто настройкой «какого-то» контроллера как root без какой-либо презентации в начале.

Удалены:

[[self rootController] presentViewController:controller animated:YES completion:^{

       [self window].rootViewController = controller;

       [[self window] makeKeyAndVisible];}];

Просто сделайте как root без каких-либо презентаций:

 [[self window] setRootViewController:controller];
averem
источник
1
Это была именно моя проблема. Пытался представить его с помощью UIModalTransitionStyleCrossDissolve, а затем сделать его rootViewController. После этого все другие презентации не работали с данным предупреждением. Просто установив его как rootViewcontroller без анимации, сделали свое дело. Спасибо!
Бернардо Оливейра
7

Одним из решений этого является, если у вас есть childviewcontroller Таким образом, вы просто представляете viewviewcontroller на его родительском

[self.parentViewController presentViewController:viewController animated:YES completion:nil];

А для отклонения используйте тот же контроллер dismissview.

[self dismissViewControllerAnimated:YES completion:nil];

Это идеальное решение работает для меня.

Гаган Джоши
источник
7

Используйте [self.navigationController presentViewController:xxx animated:YES completion:nil]в iOS 8.

Тао Фан
источник
5

Попробуйте этот код

UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:<your ViewController object>];

[self.view.window.rootViewController presentViewController:navigationController animated:YES completion:nil];
Влад
источник
4

Попробуйте представить, TabBarControllerесли это TabBarControllerприложение на основе.

[self.tabBarController presentViewController:viewController animated:YES completion:nil];

Причина может быть selfдитя, TabBarControllerи вы пытаетесь представить из ChildViewController.

Warif Akhand Rishi
источник
4

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

[self.parentViewController presentViewController:alertController animated:YES completion:nil];
Сивасагар Палакурти
источник
3

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

Допустим, у вас есть yourMainViewController, затем вы добавляете новый контроллер с именем controllerA, и затем вы хотите представить новый контроллер с именем controllerB от controllerA

Вы должны написать что-то вроде этого:

[self addChildViewController:controllerA]; //self is yourMainViewController
[self.view addsubView:controllerA.view]; 

и в controllerA вы можете представить новый контроллер без предупреждений

[self presentViewController:controllerB animated:YES completion:nil]; //self is controllerA
Chuy47
источник
3

В Swift 4.1 и Xcode 9.4.1

Решение

DispatchQueue.main.async(execute: {
    self.present(alert, animated: true)
})

Если напишите так, я получаю ту же ошибку

let alert = UIAlertController(title: "title", message: "message", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .default, handler: { action in
    })
alert.addAction(defaultAction)

present(alert, animated: true, completion: nil) 

Я получаю ту же ошибку

Presenting view controllers on detached view controllers is discouraged <MyAppName.ViewController: 0x7fa95560Z070>.

Полное решение

let alert = UIAlertController(title: "title", message: "message", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .default, handler: { action in
     })
alert.addAction(defaultAction)
//Made Changes here    
DispatchQueue.main.async(execute: {
    self.present(alert, animated: true)
})
IOS
источник
Запуск его через DispatchQueue, как это работает для меня. Я делаю executeSegue для модального контроллера представления, вызываемого из viewDidLoad на моем первом контроллере представления (вводный экран первого запуска для ориентации новых пользователей). Он загружался нормально, но выдает предупреждение. Обтекание вызова executeSegue в асинхронном вызове DispatchQueue устраняет предупреждение. Спасибо!
Грант Нойфельд
1

Убедитесь, что у вас есть контроллер корневого представления для начала. Вы можете установить его в didFinishLaunchingWithOptions.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    [window setRootViewController:viewController];
}
samwize
источник
1

Много причин для этого предупреждения. Мой, потому что у меня есть переход, связанный с ViewController к другому, который будет представлен модально. Но ViewController, от которого я представляю, динамически генерируется PageViewController. Вот почему он отделен в раскадровке. Мое приложение не будет зависать из-за этого; но я хотел бы заставить замолчать предупреждение.

Ли Проберт
источник
1

Я достиг этой темы, где у меня есть пользовательская панель навигации, и я вызывал через нее AlertViewController.

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

Вы должны добавить свой Zoomed Image View Controller дочерний элемент основного ViewController.

(например)

[self addChildViewController:ZoomedImageViewController];

Тогда вы сможете вызвать ваш ZoomedImageViewController

[self presentViewController:ZoomedImageViewController];
Навид Аббас
источник
1

Многие ответы верны.

  • Убедитесь, что у вашего представленияViewController есть parentViewController или нет.
  • Если нет, добавьте это куда-то, это должно быть добавлено
  • в противном случае, проверьте, что его parentViewController рекурсивно имеет parentViewController, пока каждый viewController не имеет родителя

Эта проблема произошла со мной, когда мой коллега добавил AViewController в BViewController. Каким-то образом он просто добавляет представление AViewController в представление BViewController.

Исправлено добавлением bViewController.addChild (aViewController)

Джером Ли
источник
1
Спасибо! добавление addChild в мой блок завершения Hero.shared.transition полностью решило мою проблему.
Landnbloc
0

Это зависит от того, хотите ли вы показать свое предупреждение или что-то подобное в любом месте вида UIViewController.

Вы можете использовать этот пример кода:

UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Alert" message:@"Example" preferredStyle:UIAlertControllerStyleAlert];

UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:nil];

[alert addAction:cancelAction];


[[[[[UIApplication sharedApplication] delegate] window] rootViewController] presentViewController:alert animated:true completion:nil];
Fabio
источник
С вашим кодом он не работает и выдает этот журналAttempt to present <UIAlertController: 0x7fc01a1eb600> on <ViewController: 0x7fc019821e00> whose view is not in the window hierarchy!
Навид Аббас