Для чего нужны сегменты Unwind и как вы их используете?

584

В iOS 6 и Xcode 4.5 появилась новая функция, которая называется «Unwind Segue»:

Размотка сегментов может позволить переход к существующим экземплярам сцен в раскадровке.

В дополнение к этой краткой записи в заметках о выпуске Xcode 4.5, у UIViewController теперь есть пара новых методов:

- (BOOL)canPerformUnwindSegueAction:(SEL)action fromViewController:(UIViewController *)fromViewController withSender:(id)sender
- (UIViewController *)viewControllerForUnwindSegueAction:(SEL)action fromViewController:(UIViewController *)fromViewController withSender:(id)sender
- (UIStoryboardSegue *)segueForUnwindingToViewController:(UIViewController *)toViewController fromViewController:(UIViewController *)fromViewController identifier:(NSString *)identifier

Как работают размоточные сегы и для чего они могут быть использованы?

Имре Келеньи
источник

Ответы:

1267

В двух словах

Размотки перехода (иногда называемый выход Segue ) можно использовать для перемещения вперед через толчок, модальные или поповер перетекает (как если бы вы совали навигационный элемент из панели навигации, закрыли поповер или отклонили модально представленный контроллер представления). Кроме того, вы можете развернуть не только один, но и несколько сегментов push / modal / popover, например, «вернуться назад» на несколько шагов в иерархии навигации с помощью одного действия раскрутки.

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

Objective-C:

- (IBAction)unwindToThisViewController:(UIStoryboardSegue *)unwindSegue
{
}

Swift:

@IBAction func unwindToThisViewController(segue: UIStoryboardSegue) {
}

Имя этого метода действия используется, когда вы создаете сценарий раскрутки в раскадровке. Кроме того, этот метод вызывается как раз перед тем, как выполняется процесс раскрутки. Вы можете получить контроллер представления источника из переданного UIStoryboardSegueпараметра для взаимодействия с контроллером представления, который инициировал переход (например, для получения значений свойств модального контроллера представления). В этом отношении метод имеет функцию, аналогичную prepareForSegue:методу UIViewController.

Обновление iOS 8: сегменты Unwind также работают с адаптивными сегментами iOS 8, такими как Show and Show Detail .

Пример

Давайте рассмотрим раскадровку с контроллером навигации и тремя контроллерами дочернего представления:

введите описание изображения здесь

Из Green View Controller вы можете развернуть (перейти назад) в Red View Controller. От Blue вы можете раскрутиться в Green или Red через Green. Чтобы включить разматывание, вы должны добавить специальные методы действий в красный и зеленый, например, вот метод действия в красном:

Objective-C:

@implementation RedViewController

- (IBAction)unwindToRed:(UIStoryboardSegue *)unwindSegue
{
}

@end

Swift:

@IBAction func unwindToRed(segue: UIStoryboardSegue) {
}

После добавления метода действия вы можете определить последовательность раскрутки в раскадровке, перетаскивая элемент управления на значок «Выход». Здесь мы хотим раскрутить Red с Green при нажатии кнопки:

введите описание изображения здесь

Вы должны выбрать действие, которое определено в контроллере представления, к которому вы хотите вернуться:

введите описание изображения здесь

Вы также можете размотаться в Red from Blue (который находится в двух шагах от стека навигации). Ключ выбирает правильное действие размотки.

Перед выполнением последовательности действий вызывается метод действия. В этом примере я определил переход от Red к Green и Blue. Мы можем получить доступ к источнику раскрутки в методе действия через параметр UIStoryboardSegue:

Objective-C:

- (IBAction)unwindToRed:(UIStoryboardSegue *)unwindSegue
{
    UIViewController* sourceViewController = unwindSegue.sourceViewController;

    if ([sourceViewController isKindOfClass:[BlueViewController class]])
    {
        NSLog(@"Coming from BLUE!");
    }
    else if ([sourceViewController isKindOfClass:[GreenViewController class]])
    {
        NSLog(@"Coming from GREEN!");
    }
}

Swift:

@IBAction func unwindToRed(unwindSegue: UIStoryboardSegue) {
    if let blueViewController = unwindSegue.sourceViewController as? BlueViewController {
        println("Coming from BLUE")
    }
    else if let redViewController = unwindSegue.sourceViewController as? RedViewController {
        println("Coming from RED")
    }
}

Разматывание также работает через комбинацию push / модальных сегментов. Например, если бы я добавил еще один контроллер представления Yellow с модальным переходом, мы могли бы вернуться от Yellow до Red за один шаг:

введите описание изображения здесь

Разматывание из кода

Когда вы определяете последовательность раскручивания путем перетаскивания элемента управления на символ Выход из контроллера представления, в структуре документа появляется новая последовательность:

введите описание изображения здесь

Выбор перехода и переход к инспектору атрибутов открывает свойство «Идентификатор». Используйте это, чтобы дать уникальный идентификатор вашей теме:

введите описание изображения здесь

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

Objective-C:

[self performSegueWithIdentifier:@"UnwindToRedSegueID" sender:self];

Swift:

performSegueWithIdentifier("UnwindToRedSegueID", sender: self)
Имре Келеньи
источник
12
+1 отличный ответ. Они звучат очень хорошо, но не могут ли методы понравиться dismissViewControllerAnimated:completion:или popViewControllerAnimated:достичь одного и того же?
Сэм Спенсер
32
Конечно, они могут. Однако, если вы используете раскадровки, то раскручивание сегментов часто позволяет добиться того же результата с гораздо меньшим количеством кода. На самом деле, теперь вы можете отклонить модально представленный контроллер представления без написания какого-либо кода. Конечно, есть еще много случаев, когда закрытие контроллеров из кода является правильным решением.
Имре Келеньи
7
Обязательно добавьте свой метод действия в заголовочный файл, иначе Storyboard не узнает об этом.
Кайл C
17
Другое преимущество перед dismissViewControllerAnimated:completion:или popViewControllerAnimated:заключается в том, что вызывается метод, который вы добавили в контроллер представления, с которым вы раскручиваете, и, таким образом, у вас есть простой способ узнать, что представленный контроллер представления завершен без необходимости превращать представляющий контроллер представления в делегат представленного контроллера представления. ,
Honus
8
Могу ли я предложить небольшое редактирование? Не было «очевидно» ясно, что вы поставили - (IBAction) unwindTRed: (UIStoryboardSegue *) unwindSegue в RedViewController.m, и, в свою очередь, это универсально доступно в «любом» из зеленых кнопок выхода для любой раскадровки. Фантастический ответ, и теперь я буду использовать это для других вопросов. Спасибо!
Джон Баллинджер
166

Что касается того, как использовать раскручивать сегы в StoryBoard ...

Шаг 1)

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

Objective-C

- (IBAction)unwindToViewControllerNameHere:(UIStoryboardSegue *)segue {
    //nothing goes here
}

Обязательно также объявите этот метод в вашем .h файле в Obj-C

стриж

@IBAction func unwindToViewControllerNameHere(segue: UIStoryboardSegue) {
    //nothing goes here
}

Шаг 2)

В раскадровке перейдите к представлению, от которого вы хотите отмотаться, и просто перетащите переход с вашей кнопки или чего-либо еще на маленький оранжевый значок «ВЫХОД» в правом верхнем углу исходного представления.

введите описание изображения здесь

Теперь должна быть возможность подключиться к «- unwindToViewControllerNameHere»

Вот и все, ваш переход будет раскручиваться при нажатии кнопки.

Трэвис М.
источник
5
Я обнаружил, что с Xcode 4.5 и ранее необходимо было объявить IBAction в заголовке. Я не знаю, правда ли это до сих пор.
Стивен Фишер
2
Есть ли способ сделать Шаг 2 без раскадровки, то есть программно? Моя раскадровка (конструктор интерфейса) испорчена и не показывает раскручивающиеся сегменты (ошибка xcode).
Ван Ду Тран
46

Сегменты размотки используются для «возврата» к какому-либо контроллеру представления, из которого через несколько сегментов вы попадаете к «текущему» контроллеру представления.

Представьте, что у вас есть что-то MyNavControllerс Aкорневым контроллером представления. Теперь вы используете толчок к B. Теперь у контроллера навигации есть A и B в его viewControllersмассиве, и B виден. Теперь вы представляете Cмодально.

В случае раскручивания сегментов вы можете теперь раскручивать «назад» из Cв B(т. Е. Отклонять модально представленный контроллер представления), в основном «отменяя» модальный переход. Вы даже можете полностью откатиться назад к контроллеру корневого представления A, отменив модальный переход и переходный процесс.

Размотка сегментов позволяет легко вернуться. Например, до iOS 6, лучшая практика для отклонения представленных контроллеров представления состояла в том, чтобы установить представляющий контроллер представления в качестве делегата представленного контроллера представления, затем вызвать ваш пользовательский метод делегата, который затем отклоняет представленный ViewViewController . Звучит громоздко и сложно? Это было. Вот почему разматывать сегы это приятно.

Ян Мейер
источник
7
Вы можете позвонить dismissViewController:animatedс представленного контроллера. Вам не нужно делегировать это. Конечно, если вам нужно передать данные обратно, вам понадобится делегирование или какой-то другой метод.
mxcl
3
В то время как вы можете вызывать dismissViewController:animated:из представленного контроллера, «наилучшей практикой» было на самом деле вызвать метод делегата на представляющем контроллере, чтобы сделать это для вас, как упоминал Ян.
Крис Нолет
36

Кое-что, чего я не видел, упоминалось в других ответах здесь, это то, как вы справляетесь с раскручиванием, когда не знаете, откуда возникла первоначальная реакция, что для меня является еще более важным вариантом использования. Например, скажем, у вас есть справочный контроллер просмотра ( H ), который вы отображаете модально с двух разных контроллеров представления ( A и B ):

AH
BH

Как настроить переход с обратной стороны, чтобы вернуться к правильному контроллеру просмотра? Ответ заключается в том, что вы объявляете действие по отмене в A и B с одинаковыми именами , например:

// put in AViewController.swift and BViewController.swift
@IBAction func unwindFromHelp(sender: UIStoryboardSegue) {
    // empty
}

Таким образом, раскручивание найдет тот контроллер представления ( A или B ), который инициировал переход, и вернется к нему.

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

shawkinaw
источник
2
Спасибо за эту информацию, я искал это.
Мадху
2
действительно здорово упомянуть эту информацию, так как я уже внедряю решение, и ничего не произойдет, пока я не получу ваш совет здесь, большое спасибо за вашу поддержку
Amr Angry
Это отличная информация! Большое спасибо!
Доминик Флакон
24

Swift iOS:

Шаг 1: определите этот метод в виде вашего контроллера MASTER. в который вы хотите вернуться:

//pragma mark - Unwind Seques
@IBAction func goToSideMenu(segue: UIStoryboardSegue) {

    println("Called goToSideMenu: unwind action")

}

Шаг 2: (StoryBoard) Щелкните правой кнопкой мыши на кнопке SLAVE / CHILD EXIT и выберите «goToSideMenu». В качестве действия подключите кнопку «Button», на которую вы нажмете, чтобы вернуться к своему представлению контроллера MASTER:

введите описание изображения здесь Шаг 3: Построить и запустить ...

Винод Джоши
источник
1

Например, если вы перейдете от viewControllerB к viewControllerA, то в вашем viewControllerA ниже будет вызван делегат и данные будут предоставлены.

@IBAction func unWindSeague (_ sender : UIStoryboardSegue) {
        if sender.source is ViewControllerB  {
            if let _ = sender.source as? ViewControllerB {
                self.textLabel.text = "Came from B = B->A , B exited"
            }
            
        }

}
  • Размотайте контроллер просмотра исходного кода Seague (необходимо подключить кнопку выхода к значку выхода VC и подключить его к размотке:

введите описание изображения здесь

  • Unwind Seague Completed -> TextLabel для viewControllerA изменен.

введите описание изображения здесь

Технология
источник