Связывание контроллеров дочерних представлений с контроллером родительских представлений в раскадровке


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

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

Что я должен сделать с контейнером VC, чтобы принять дочерние VCs?

5 56

5 ответов:

как что-то из комбинации ответов Калеба и Мэтта, я сделал:

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"cpdc_check_embed"]) {
        self.checkVC = segue.destinationViewController;
    }
}

...где checkVC - это свойство контроллера контейнера:

@property (weak,nonatomic) PXPCheckViewController * checkVC;

вы просто должны установить embed Продолжение ТУТ Storyboard ID все, что вы хотите (в данном случае, cpdc_check_embed):

check embed screen in Xcode

...а затем проверьте идентификатор в -prepareForSegue:sender:.

все еще не выход, но чище, чем у Мэтта (ИМХО) и более конкретный, чем у Калеба, и вы все еще получаете симпатичная раскадровка:

enter image description here

раскадровка имеет дело со встроенными контроллерами представления контейнера очень хорошо, отображая сегменты для дочерних / корневых контроллеров представления, так что отношения четко показаны. Также приятно, как дочерние и родительские контроллеры представления разделены на разные сцены.

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

хотя это невозможно, было бы неплохо, если бы я мог создать IBOutlets от контроллера вида контейнера к его дочерним элементам в разных сценах, а затем, когда отображается мой контроллер вида контейнера, установите отношения родитель / потомок в соответствии к правилам, описанным в документация UIViewController. Если бы у нас были ссылки на наши "левые" и "правые" дочерние контроллеры представления, то мы могли бы установить отношения без проблем.

стандартным решением этой проблемы ссылок является создание ссылок на дочерние контроллеры представления путем перетаскивания Object выходы в сцену контроллера вида контейнера, а затем указание их типа класса как экземпляров дочернего контроллера вида занятия.

чтобы держать детей разделенными в разных сценах, таких как встроенные контейнеры Apple, однако, мы будем использовать другой трюк. Во-первых, предположим, что у нас есть следующие свойства, объявленные в нашем классе контейнера,ContainerViewController:

@property (nonatomic, strong, readwrite) UIViewController *leftViewController;
@property (nonatomic, strong, readwrite) UIViewController *rightViewController;

в нашей раскадровке выберите сцену, представляющую "левый" контроллер вида. В инспекторе атрибутов установите контроллер вида identifier свойство "cvc_leftViewController" ("cvc_" относится к ContainerViewController, но действительно идентификатор может будьте все, что вы хотите). Сделайте то же самое для сцены правого контроллера вида, установив его идентификатор в "cvc_rightViewController".

теперь вставьте следующий код в ContainerViewController ' s viewDidLoad способ:

if (self.storyboard) {
    _leftViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"cvc_leftViewController"];
    _rightViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"cvc_rightViewController"];
}

, когда ContainerViewController загружается из раскадровки, он будет захватывать "левый" и "правый" контроллеры вида из их соответствующих сцен и устанавливать ссылки на них через свои свойства. Теперь, когда у вас есть контроль над экземплярами контроллера дочернего представления, вы можете настроить родительский / дочерний отношения, как вам нравится. Чтобы узнать, как это сделать правильно, обратитесь к документация UIViewController.

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

Edit: хотя это совершенно не нужно и ничего не значит, если вы действительно действительно хотите, чтобы раскадровка отображала соединения из вашего контейнера с контроллерами дочерних представлений как и встроенные контейнеры Apple, просто используйте мой метод выше, а затем установите сегменты непосредственно между сценой контейнера и дочерними сценами и просто никогда не выполняйте эти сегменты. Теперь все будет работать правильно и выглядеть красиво тоже.

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

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

вы, вероятно, спрашиваете об этом, потому что хотите передать некоторые информация от одного контроллера вида к другому при переходе от одной сцены к другой. Способ сделать это при работе с раскадровками-переопределить -prepareForSegue:sender: в одном или обоих контроллерах представления, на которые влияет сегмент. Объект UIStoryboardSegue, предоставленный в и sourceViewController и destinationViewController свойства, а также identifier собственность. Эти свойства можно использовать для определения сегмента, который будет передавать данные между контроллерами представления.

Ray Блог вендерлих имеет хороший двух частей учебное пособие по использованию раскадровки, которые могут помочь вам:

  • Часть 1 охватывает настройку проекта раскадровки, добавление сцен и создание сегментов.

  • Часть 2 имеет дело с использованием сегментов для перехода между сценами, в том числе prepareForSeque метод, упомянутый выше.

iOS 5 позволяет нескольким контроллерам просмотра быть активными в одной сцене (хотя один все еще должен быть ответственным), поэтому одна сцена в вашей раскадровке может иметь несколько контроллеров. Вы можете использовать розетки для подключения этих контроллеров друг к другу, и вы можете настроить эти соединения так же, как и в IB: control-перетаскивание с одного контроллера на другой в той же сцене. Обычный список розеток откроется, чтобы вы могли выбрать, какую розетку подключить.

ключ к использованию нескольких контроллеров в одной сцене (что я считаю, что вы здесь) использует таинственный объект из списка объектов в IB для представления другого контроллера вида и подключения его выходов.

ответ как создать пользовательский контейнер контроллера вида с помощью раскадровки в iOS 5 должно помочь, я надеюсь. Ответ также предоставляет рабочий пример приложения, которое очень полезно.

проблема с ответом @Ben (в противном случае разумным) заключается в том, что он работает только на одном уровне вложенности. Кроме того, потребуется, чтобы каждый последующий VC был настроен для сохранения контроллера вложенного представления в prepareForSegue.

чтобы решить эту проблему, я потратил слишком много времени на изучение индекса на основе NSObject, который вы могли бы добавить в раскадровку, привязать к сцене, а затем зарегистрировать его Родительский VC в Глобальном индексе на основе типа и restorationId. Эта работа / может работать, но слишком много усилий в конце концов, и по-прежнему требует двухэтапного процесса визуальной привязки и программного поиска.

для меня самое простое и общее решение-лениво спускаться по иерархии контроллера вида

в моем простом тестовом проекте я добавил следующие строки для viewDidLoad:

    self.left.data = [
        "Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro.",
        "De carne lumbering animata corpora quaeritis." ]

здесь left определено как:

lazy var left:CollectionViewController = { [unowned self] in
    return self.childViewControllerWithId("Left") as! CollectionViewController }()

и childViewControllerWithId определено как:

extension UIViewController {
    func childViewControllerWithId(rid:String) -> UIViewController? {

        // check immediate child controllers
        for vc in self.childViewControllers as! [UIViewController] {
            if vc.restorationIdentifier == rid { return vc }
        }

        // check nested controllers
        for vc in self.childViewControllers as! [UIViewController] {
            if let vc = vc.childViewControllerWithId(rid) {
                return vc
            }
        }

        assert(false, "check your assumptions")
        return nil
    }
}

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

и чтобы заявить, что, надеюсь, очевидно, вам не нужно реализовывать prepareForSegue, и вам не нужно использовать ленивую загрузку, вам просто нужно позвонить find(...).