Делегат против 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 - отличный способ чистой и уникальной пары двух классов. Я настоятельно рекомендую его.