Swift - сохранить настройку ViewController после перехода

На данный момент я должен ViewControllers. Вы можете переключаться между ViewControllerA и ViewControllerB с помощью show-segues. Проблема в том, что каждый раз, когда я переключаюсь обратно, состояние ViewControllers сбрасывается. Как я могу сохранить настройку ViewController?

От А до Б

    @IBAction func editButtonTapped(_ sender: Any) {
    let imageCollectionView = self.storyboard?.instantiateViewController(withIdentifier: "ImageCollectionVC") as! ImageCollectionViewController

    self.navigationController?.pushViewController(imageCollectionView, animated: true)
}

От Б к А

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    tappedImage = images[indexPath.row]
    performSegue(withIdentifier: "backToPopUpView", sender: self)

}

person Chris    schedule 08.11.2019    source источник
comment
Проблема в том, что каждый раз, когда я переключаюсь обратно, состояние ViewControllers сбрасывается. Тогда вы фактически не переключаетесь обратно. Можете ли вы показать код, чтобы мы знали, что вы сейчас делаете?   -  person Sweeper    schedule 08.11.2019
comment
я отредактировал свой вопрос   -  person Chris    schedule 08.11.2019
comment
Глядя на свой код, вы не перемещаетесь вперед и назад между контроллерами представления, а создаете новый экземпляр контроллера представления при каждом изменении. Таким образом, вы на самом деле делаете A › B › A1 › B1 › A2 › B2 и т. д., поэтому состояние не сохраняется. Вам нужно открыть контроллер представления B, чтобы вернуться к A. Кстати, вы также не используете переход от A к B.   -  person flanker    schedule 08.11.2019
comment
Возможный дубликат Передача данных между контроллерами представления   -  person Yoel Jimenez del valle    schedule 08.11.2019
comment
@flanker, так как мне это сделать?   -  person Chris    schedule 09.11.2019
comment
@Chris - смотрите мой ответ ниже, где я подробно рассказываю об этом.   -  person flanker    schedule 09.11.2019


Ответы (2)


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

  • последовательный метод навигации: переходы или нажатие/выталкивание с помощью навигационного контроллера или модальное представление/закрытие, но не их сочетание для одного А-Б-А переход

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

В приведенном ниже примере навигация осуществляется через контроллер навигации, а изображение используется в качестве примера того, как передать данные обратно родительскому элементу. Это должно быть тривиально, чтобы адаптировать это для других обстоятельств.

Дочернему классу нужен согласованный интерфейс с его родителем, чтобы он мог взаимодействовать. Делается это протоколом. В этом примере мы предоставляем дочернему элементу возможность передать свое обновленное изображение обратно родителю:

protocol ClassBDelegate {
    func childVCDidComplete(with image: UIImage?)
}

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

class B: UIViewController {
    var delegate: ClassBDelegate?

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        tappedImage = images[indexPath.row]
        delegate?.childVCDidComplete(with: tappedImage)
        navigationController?.popViewController(animated: true)
    }
}

Чтобы все это работало, делегат дочернего контроллера представления должен быть установлен так, чтобы он указывал на его родительский контроллер представления (A), но прежде чем это может произойти, этот класс должен соответствовать протоколу:

extension A: ClassBDelegate {}
    func childVCDidComplete( with image: UIImage?) {
        self.image = image
    }
}

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

Class A: UIViewController {
    var image: UIImage?

    @IBAction func editButtonTapped(_ sender: Any) {
        let imageCollectionView = self.storyboard?.instantiateViewController(withIdentifier: "ImageCollectionVC") as! ImageCollectionViewController
        imageCollectionView.delegate = self
        self.navigationController?.pushViewController(imageCollectionView, animated: true)
    }
}
person flanker    schedule 08.11.2019
comment
извините, но я изо всех сил пытаюсь реализовать это в своем коде. Где именно мне нужно реализовать extension и protocol? - person Chris; 11.11.2019
comment
Я использовал A и B в качестве сокращений для ваших контроллеров представлений A и B, поэтому замените их соответствующими именами классов. Затем вы реализуете протокол либо в его собственном файле, либо в том же файле, что и контроллер представления B, между операторами импорта и определением вашего класса. Вы помещаете расширение для просмотра контроллера A под его определением класса - после последнего }. Это слишком широко, чтобы объяснять здесь все о протоколах/делегатах, но если вы посмотрите на YouTube, у Шона Аллена есть очень хороший видеоурок. - person flanker; 11.11.2019
comment
Я реализовал это, но теперь, если я нажму на элемент, ничего не произойдет - person Chris; 11.11.2019
comment
popViewController ничего не делает, хотя и вызывается, я тестировал его с помощью print - person Chris; 11.11.2019
comment
я подозреваю, что вы не совсем правильно его реализовали, или есть другой код, который вы не показали, конфликтующий с ним, поскольку я скопировал код из рабочего макета. Какой пункт, где ничего не делает? popviewcontroller будет работать только в том случае, если вы изначально представили контроллер представления с помощью push (с контроллером навигации), а не в том случае, если вы представили модально или использовали переход. - person flanker; 11.11.2019
comment
Я думаю, что сделал это. Я скопировал вашу версию editButtonTapped - person Chris; 11.11.2019
comment
Итак, у меня все еще был segue в моем Storyboard, который я только что удалил, но теперь editButtonTapped не приводит меня к другому Viewcontroller - person Chris; 11.11.2019
comment
Вам необходимо убедиться, что кнопка редактирования связана с ее IBAction и что код в ней введен точно (с использованием правильных имен классов и строк идентификаторов) и выполняется, и что ни одна из необязательных цепочек не возвращает nil. - person flanker; 12.11.2019
comment
Давайте продолжим обсуждение в чате. - person Chris; 12.11.2019
comment
Извини, Крис, я старался изо всех сил помочь, но у меня действительно нет времени тратить время на болтовню об этом. Переход между контроллерами представлений — это основа разработки Swift, а не то, что даже нужно обсуждать на SO. Если вы боретесь, есть много хороших руководств по таким темам. - person flanker; 12.11.2019
comment
проблема, с которой я столкнулся при переходе, на самом деле была более глубокой проблемой, но теперь я справился с ней. Но я реализовал ваш код, и он у меня не работает :( - person Chris; 12.11.2019
comment
Если вы продвинулись дальше, возможно, опубликуйте свой обновленный код в виде нового поста с более конкретным вопросом? - person flanker; 12.11.2019

Вы создали новый ViewControllerA, и у вас есть следующий результат A -> B -> A. Но это не так, вы должны отклонить ViewControllerB...

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    tappedImage = images[indexPath.row]
    self.dismiss(animated: true, completion: nil)
    //performSegue(withIdentifier: "backToPopUpView", sender: self)

}
person KNK    schedule 08.11.2019
comment
но я передаю UIImage с этим переходом. И если я просто self.dismiss это изображение не будет передано - person Chris; 08.11.2019
comment
Вы должны передавать информацию двумя способами. 1. С протоколом 2. В ViewControllerB у вас должно быть свойство parentVC: ViewControllerA или vcA: ViewControllerA... А в ViewControllerA вы должны написать эту строку imageCollectionView.vcA = self. А в ViewControllerB можно передать self.vcA.image = tappedImage - person KNK; 08.11.2019
comment
не могли бы вы уточнить это, пожалуйста? :) Я не могу написать imageCollectionView.vcA = self в ViewControllerA - person Chris; 11.11.2019