Делегат против Unwind Segue для передачи данных в родительскую сцену
Так как iOS 6, для разворачивания иерархии сцены доступны разматывающиеся сегменты. Я пытаюсь принять решение о более чистом/улучшенном/предпочтительном/более ремонтопригодном методе передачи данных в родительский контроллер представления. Есть несколько вопросов, которые касаются этого с технической точки зрения (например, "если у меня есть необходимость, мне еще нужен делегат" ), но я не могу найти много того, что касается вопросов плюсов и минусов.
Вариант 1: используйте делегат.
- Выполнено путем передачи в родительском контроллере представления в качестве делегата, придерживающегося протокола.
- Ребенок вызывает метод протокола для возврата данных.
- Если для родителя требуется проверка данных, возвращаемое значение /dict требуется, чтобы разрешить ребенку обрабатывать ошибки.
- Накладные расходы: определение протокола и один метод в родительском (для проверки и получения данных).
Вариант 2: используйте разматывающий сегмент
- Выполнено, вызвав разворот segue от ребенка.
- Ребенок добавляет segue на свою сцену, перетаскивая кнопку или раскадровку непосредственно в
Exit
и называя segue, так что это может быть с performSegueWithIdentifier:sender
- Parent реализует
returnFromSegueName
(пользовательский метод, связанный с этим сеансом), чтобы захватить данные из дочернего элемента.
- Проверка данных, хотя может быть реализована только путем реализации
canPerformUnwindSegueAction:fromViewController:withSender
- Ошибка проверки данных потребует другого свойства для дочернего элемента, поскольку этот метод принимает только значение BOOL для возвращаемого значения.
- Накладные расходы: два метода, дополнительное свойство и махинации раскадровки.
В целом, делегаты чувствуют себя как более чистый путь, но, возможно, также устарели. Неужели я ошибаюсь, чтобы наклоняться в этом направлении?
Ответы
Ответ 1
Теперь я понимаю, что на самом деле это не ответительный вопрос, кроме как сказать, что ни один подход не является неправильным - у них обоих есть свои плюсы и минусы. После того, как вы занялись в течение недели и сделали больше чтения по этому вопросу, я могу, по крайней мере, количественно определить, почему вы, возможно, захотите использовать отключенный сеанс или делегаты для работы между контроллерами представлений.
Сцепление
Обе модели примерно одинаково (слабо) связаны. Под капотом развязка segue - это просто делегат, где iOS выполнил работу по подключению к вам. Для делегатов родитель знает и соответствует дочернему протоколу. Для разматывания родитель должен быть подключен к ребенку на раскадровке для размотки и должен знать свойства ребенка для извлечения возвращаемых данных. Однако, если вы новичок в делегированиях и хотите получить некоторые данные из дочернего представления, разматывание секций, вероятно, менее устрашающее, чем использование протоколов с делегатами.
Гибкость
Отрывные сегменты - это только хороший выбор, если единственная цель взаимодействия между родителями и родителями - вернуть данные. Кажется, что не существует способа отменить разворот segue. Поэтому, если родитель должен выполнить какую-либо проверку данных, или если ребенку требуется более одного взаимодействия с родителем, единственный способ сделать это - иметь делегат, где несколько методов могут быть возвращены родителям.
ремонтопригодность
Если тип или другие аспекты возвращаемых данных изменяются, будет проще обновить разворот segue, поскольку все, что вам нужно сделать, - это обновить код в вашем режиме размотки, чтобы посмотреть на новые свойства. Для подхода протокола/делегата вам придется обновить протокол в дочернем процессе и реализацию в родительском. Однако простота разматывания происходит за счет того, что вы можете легко пропускать места в контроллерах родительских представлений, которые требуют обновления, потому что у вас нет компилятора, проверяющего ваш контракт (протокол).
Победитель
Нет. Каким образом вы идете, зависит от ваших потребностей в данных, уровня комфорта с протоколами (они выглядят более устрашающе на первый взгляд, чем они должны), сложность вашего приложения и долгосрочные потребности в обслуживании.
В моих целях я закончил работу с делегатами, потому что в некоторых случаях моему ребенку приходилось делать несколько обращений к родителям. Однако в некоторых случаях, когда у меня было много данных для передачи данных, я принял то, что я узнал из разворачиваемого сеанса, и просто использовал свойства у ребенка, из которого родитель мог извлечь необходимую информацию. Я также использовал это как удобный путь для родителя, чтобы предоставить информацию об ошибке ребенку. Я не смешиваю и не соглашаюсь с делегатами в программе для согласованности с партнером по программированию, но нет причин, по которым вы не могли бы этого сделать, если хотите.
Ответ 2
Я очень скептически относился к раскадровки, но я решил погрузиться и использовать их в новом проекте. Я был поражен легкостью, с которой вы можете общаться между двумя контроллерами. Когда вы выполняете performSegueWithIdentifier, вы получаете дескриптор нового ViewController. Вы можете установить любые открытые свойства, которые вы хотите в этом новом viewController, очень чисто и красиво.
Вот пример:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:@"showDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
Student *student = [self.students objectAtIndex:indexPath.row + [self rowAdjuster]];
[[segue destinationViewController] setStudent:student];
}
}
Это очень красиво и аккуратно. Нет специального протокола, который необходимо отслеживать или поддерживать.
И затем вернемся назад (у меня есть IBAction, связанный с кнопкой в моем подробном представлении). Вы можете снова получить хорошую чистую ссылку на viewController, к которой вы возвращаетесь, и действовать на этот viewController.
- (IBAction)returnWithStudent:(UIStoryboardSegue *)segue {
UIViewController *vc = [segue sourceViewController];
if ([vc isKindOfClass:[ AddStudentViewController class]]) {
AddStudentViewController *addViewController = (AddStudentViewController *)vc;
if (addViewController.student != nil) {
if ([addViewController hasTakenPhoto]) {
[PhotoHelpers saveImageForStudent:addViewController.student];
}
[StudentController updateStudent:addViewController.student];
}
}
}
Также логический контроль segue хорош. Можно выполнить логические проверки в shouldPerformSegue, которые весьма удобны.
Я видел много кода junky, в котором используются протоколы "отправить что-то обратно вызывающему", которые действительно плохо подходят для классов связи. Он делает трехстороннюю компоновку - viewController1 → protocol → viewController2, тогда как segues создают приятное расположение viewController1- > viewController2.
Segue - отличный способ чистой и уникальной пары двух классов. Я настоятельно рекомендую его.