Ссылка IBOutlet на встроенный контроллер представления
-
12-12-2019 - |
Вопрос
У меня есть сложное представление iPad, которым я управляю с помощью нескольких контроллеров представления.Раньше (до iOS6/XCode 4.5) я делал это, выделяя контроллеры представлений в коде и подключая к ним различные представления через ссылки на главное представление.
Я хотел бы использовать новые представления контейнера для встраивания контроллеров представлений в файл раскадровки.Кажется, я не могу сделать ссылку IBOutlet на встроенный контроллер представления на главный контроллер.
Можно ли сделать это?Или получить встроенный контроллер через тег или что-то в коде?
Этот вопрос КОНКРЕТНО касается использования представлений контейнера.
Решение
Я не уверен, что вы подразумеваете под «Получение встроенного контроллера».Когда вы хотите использовать контроллер, вы используете метод Uistoryboard InstantiateViewControllerWithdiTifier:, используя идентификатор, который вы даете контроллеру в IB.Вы также можете использовать SpecialsegeWithdentifier: Sender: Method (который также создал контроллер представления).Вы должны проверить «Использование контроллеров просмотра в вашем приложении» в разделе Apple.Он также имеет отношение к тому факту, что контроллеры дочернего представления создаются одновременно, что и контроллер контейнера.
После редактирования: если вы встраиваете вид контейнера в другой контроллер представления, контроллер встроенного представления может быть указан из содержащего контроллер с Self.childViewControllers (который будет массивом, поэтому, если есть только один, вы можете получить егос lastObject).
Другие советы
Другой вариант для некоторых случаев — захват встроенного контроллера с помощью -prepareForSegue:sender:
.
Например, если у меня есть UINavigationController
встроенный в CustomContainerViewController
, я могу назвать переход к вставке embedContentStack
в раскадровке и зафиксируйте его в CustomContainerViewController
с помощью
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:@"embedContentStack"]) {
// can't assign the view controller from an embed segue via the storyboard, so capture here
_contentStack = (UINavigationController *)segue.destinationViewController;
}
}
Вот еще один поток об этом: Контроллер просмотра контейнера для доступа от родительского iOS/ a>
Они предлагают хранить ссылку в Prepareforsegegege или искать встроенный viewcontroller в Self.childViewControllers
Примечание предостережения
Прежде чем приступить к ответу на этот вопрос, вы можете подумать, действительно ли встроенные элементы должны быть контроллерами представления.
Например, если вы встраиваете UICollectionViewController
подкласс, не могли бы вы вместо этого встроить UICollectionView
подкласс?Или, еще лучше, не могли бы вы встроить UIView
подкласс, который скрывает UICollectionView
за простой ViewModel?
В базе кода, над которой я сейчас работаю, я встраиваю два контроллера представления в другой контроллер представления.Вместо этого оба могут быть простыми представлениями, и их будет легче привязать к раскадровке без этого беспорядочного кода.
К сожалению, в настоящее время они являются контроллерами представлений, и я не могу сейчас упростить их до простых представлений, так что придется сделать это.
Фон
Я использую подход, заключающийся в выборе перехода вставки в prepare(for segue:, sender:)
как было предложено Игривый Компьютерщик здесь.
Я хотел показать Swift, который я использую для этого, поскольку он кажется довольно аккуратным…
class EditionLandingViewController: UIViewController {
fileprivate var titlesView: SectionTitlesViewController!
fileprivate var sectionsView: SectionsViewController!
}
//MARK:-
extension EditionLandingViewController {
private enum SegueId: String {
case embedTitles
case embedSections
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
guard
let segueRawId = segue.identifier,
let segueId = SegueId(rawValue: segueRawId)
else { return }
switch segueId {
case .embedTitles:
self.titlesView = segue.destination as! SectionTitlesViewController
case .embedSections:
self.sectionsView = segue.destination as! SectionsViewController
}
}
}
Обсуждение
Я решил называть переходы как методы действий.
Используя enum
Случаи для идентификаторов перехода означают, что на вашей стороне есть компилятор и инструменты, поэтому гораздо сложнее ошибиться в имени перехода.
Сохранение идентификаторов перехода в private enum
в рамках extension
в данном случае область видимости кажется подходящей, поскольку эти переходы больше нигде не нужны (они не могут быть perform
изд, например).
Я использую неявно развернутые типы для встроенных контроллеров представления, потому что (во всяком случае, в моем случае) их отсутствие является логической ошибкой.
Точно так же я также рад принудительно привести типы контроллеров представления назначения.Опять же, было бы логической ошибкой, если бы эти типы не были одинаковыми.