I am having the same error that is in this question: how can i access IBOutlet in another class? in swift but when I write in my Xcode (for iOS 8 with Swift 3) I have an error.
My code is this. I want to edit amauntOut (is an UILabel) that is in the class Convert_Table_Third_Cell with the action of one button:
#IBAction func actionTextb(_ sender: Any) {
print("you writted \(String(describing: amauntEnter.text!))----")
//Convert_Table_Third_Cell.amauntOut.text = amauntEnter.text ----> is a tried
//var dash : abcViewController = storyBoard.instantiateViewControllerWithIdentifier("abc") as! abcViewController ----> is a tried
//var a = dash.getXYZ() ----> is a tried
var update: Convert_Table_Third_Cell = UIStoryboard.instantiateViewController(UIStoryboard) as! Convert_Table_Third_Cell
update.amauntOut.text = "hola"
}
I get this error:
Instance member 'instantiateViewController' cannot be used on type 'UIStoryboard'; did you mean to use a value of this type instead?
Can someone help me?
this is the first class
import UIKit
class Convert_Table_Second_Cell: UITableViewCell {
#IBOutlet var amauntEnter: UITextField!
var theNumber = getTheNumber()
#IBAction func actionTextb(_ sender: Any) {
print("you writted \(String(describing: amauntEnter.text!))----")
let storyboard = UIStoryboard.init(name: "convert ID", bundle: nil)
let update = storyboard.instantiateViewController(withIdentifier: "convert ID") as! Convert_Table_Third_Cell
update.amauntOut.text = "hola"
let aa = "hola hillel----------------------"
print(aa)
print(theNumber.usedParameters(ArrayOfNumbers: unitInOutlet, TipOfData: 3))
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
print("this is the valeu \(theNumber.hola)")
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
this is the second where is the label that I want to edit
import UIKit
class Convert_Table_Third_Cell: UITableViewCell {
#IBOutlet var amauntOut: UILabel!
#IBOutlet var UnityMeasurment: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Your approach is incorrect. A view controller is initiated when it is displayed on the screen. One and only on view controller object can be displayed at one time. In your code, you are initiating a brand new view controller and set text to outlets. So that won't work. Instead, you need to set text to the text field on the existing instance of you view controller.
To do so, in the view controller that you want to receive text field content updates, register in notification center to receive a content update function calls.
NotificationCenter.default.addObserver(self, selector: #selector(listnerFunction(_:)), name: NSNotification.Name(rawValue: "notificationName"), object: nil)
func listnerFunction(_ notification: NSNotification) {
if let data = notification.userInfo?["data"] as? String {
self.textField.text = data
}
}
Then in another view controller, if you want to send text to the above view controller and update text, simply post the data to notification center
let data:[String: String] = ["data": "YourData"]
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "notificationName"), object: nil, userInfo: data)
Instance member 'instantiateViewController' cannot be used on type 'UIStoryboard'; did you mean to use a value of this type instead?
It say that you cannot use instance member of instantiateViewController by a class of UIStoryboard.
Change var update: Convert_Table_Third_Cell = UIStoryboard.instantiateViewController(UIStoryboard) as! Convert_Table_Third_Cell
to var update: Convert_Table_Third_Cell = storyboard?.instantiateViewController(withIdentifier: {YourStoryBoardID}) as! Convert_Table_Third_Cell
Related
Hai guys I am new to iOS development and still learning
I have a three View controllers ,viewController, SViewController, TViewController
in SviewController I have notification sender.post method on clicking a button
in viewController, TViewController viewdidload() methods I have .addobserver() methods
when I click a button on SViewController and post the notification
View Controller's selector is executed and not the TviewController
I have loaded the TviewController in FirstVC i.e ViewController viewdidload() method only
since segue performs again a viewdidload() from SviewController to TviewController with another button ,I tried to allocate a completion handler string to global variable so that it value remains same and print it(changed value) when view is loaded again, then I came to know that the completion handler is not at all executing here is the code
ViewController
import UIKit
extension Notification.Name{
static var fnote = Notification.Name("fnote")
}
class ViewController: UIViewController {
#IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(fhandle(notification:)), name: .fnote, object: nil)
let storyboad = UIStoryboard(name: "Main", bundle: nil)
let tvc = storyboad.instantiateViewController(identifier: "1") as! TViewController
let _ = tvc.view
print(tvc.isViewLoaded)
print("journey")
}
#objc func fhandle(notification:Notification){
label.text = "Haii welcome to the hyderabad"
}
}
SViewController
import UIKit
var temp:String = "HHH"
class SViewController: UIViewController {
#IBAction func click(_ sender: Any) {
NotificationCenter.default.post(name: .fnote, object: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
TviewController
import UIKit
class TViewController: UIViewController {
#IBOutlet weak var label2: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(handler(notification:)) , name: .fnote, object: nil)
print(temp)
print("happy")
}
#objc func handler(notification:Notification)
{
print("jackson")
label2.text = "Hurray"
temp = label2.text ?? "Nothing"
}
}
Can Some one please help me with this
You haven't shown or explained where / when / how you're going to display the view from TViewController, but to explain the first thing you're doing wrong...
In this code:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(fhandle(notification:)), name: .fnote, object: nil)
let storyboad = UIStoryboard(name: "Main", bundle: nil)
let tvc = storyboad.instantiateViewController(identifier: "1") as! TViewController
let _ = tvc.view
print(tvc.isViewLoaded)
print("journey")
}
as soon as viewDidLoad() finishes (that is, immediately after the print("journey") line), your tvc instance of TViewController is destroyed. That is, it's dumped from memory and no code inside it can execute, because it no longer exists.
That's called "going out of scope."
So, when you try to post a notification from SViewController, there is no TViewController in existence so its code is not running to "observe" the notification.
Here is a very simple example of multiple view controllers observing a notification:
When you push from ViewController to TViewController, you get a new instance of TViewController and the original instance of ViewController still exists.
When you push from TViewController to SViewController, you get a new instance of SViewController and both ViewController and TViewController still exist.
When you tap the "Post" button, ViewController and TViewController will each execute the func you assigned to observe the notification.
When you then go Back to TViewController, you'll see its label text has changed, and when you go back to ViewController you'll see its label text has also changed.
Note that if you then push to TViewController again, you get a new instance and its label will be back at its original text.
extension Notification.Name{
static var fnote = Notification.Name("fnote")
}
class ViewController: UIViewController {
#IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(fhandle(notification:)), name: .fnote, object: nil)
print("journey")
}
#objc func fhandle(notification:Notification) {
print("Got it!")
label.text = "Haii welcome to the hyderabad"
}
}
class TViewController: UIViewController {
#IBOutlet weak var label2: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(handler(notification:)), name: .fnote, object: nil)
print("happy")
}
#objc func handler(notification:Notification) {
print("jackson")
label2.text = "Hurray"
}
}
class SViewController: UIViewController {
#IBOutlet var infoLabel: UILabel!
#IBAction func click(_ sender: Any) {
NotificationCenter.default.post(name: .fnote, object: nil)
infoLabel.text = "Notification Posted"
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
let storyboad = UIStoryboard(name: "Main", bundle: nil)
let tvc = storyboad.instantiateViewController(identifier: "1") as! TViewController
let _ = tvc.view
print(tvc.isViewLoaded)
This is not the way to test the notification. Push your "TViewController" controller from the "ViewController" controller. Then post notification from your target controller.
My work is
1 .Passing data from first view controller -> second view controller using pushViewController: Success
2 .Passing data from second view controller -> First View Controller using popViewController: Success //used delegate protocol for return data
3 .Passing data from third view controller -> First View Controller : Error
Code :
ViewController.swift
import UIKit
class ViewController: UIViewController,secondViewDelegate,thirddelegate {
#IBOutlet var Firstoutput: UILabel!
#IBOutlet var inputField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
func popdata(value: String) { //second view controller delegate protocol defintions
Firstoutput.text = "\(value)"
}
func thirdView(datas:String) //third view controller delegate protocol definition
{
print(datas)
}
#IBAction func pushBtn(_ sender: Any) { //first view button action
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vcFirst = storyboard.instantiateViewController(withIdentifier: "second") as! SecondViewController //secondview
vcFirst.Secondtext = inputField.text
vcFirst.delegate = self //second view delegate intiate
let vcThird = storyboard.instantiateViewController(withIdentifier: "third") as! ThirdViewController //third view
vcThird.thirddelegate = self //third view delegate intiate
navigationController?.pushViewController(vcFirst, animated: true)
}
}
SecondViewController.swift
import UIKit
//protocol for passing data when pop
protocol secondViewDelegate {
func popdata(value:String)
}
class SecondViewController: UIViewController {
#IBOutlet var secondOutputField: UILabel!
#IBOutlet var secondInputField: UITextField!
var Secondtext:String!
var delegate:secondViewDelegate!
override func viewDidLoad() {
super.viewDidLoad()
secondOutputField.text = Secondtext
}
//popping back to first view controller using data
#IBAction func popBtn(_ sender: Any) {
if delegate?.popdata != nil
{
delegate.popdata(value: secondInputField.text!)
}
navigationController?.popViewController(animated: true)
}
//pushing to third view controller
#IBAction func thirdPageBtn(_ sender: Any) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vcThird = storyboard.instantiateViewController(withIdentifier: "third") as! ThirdViewController
navigationController?.pushViewController(vcThird, animated: true)
}
}
ThirdViewController.swift
import UIKit
protocol thirdviewDelegate //delegate to pass data from thirs view to first view
{
func thirdView(datas:String)
}
class ThirdViewController: UIViewController {
var thirddelegate:thirdviewDelegate!
#IBOutlet var thirdTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad
}
#IBAction func thirdViewInvoke(_ sender: Any) {
if thirddelegate?.thirdView != nil
{
thirddelegate.thirdView(datas: thirdTextField.text!)
}
}
}
OutPut Screenshot :
Only passing data from third to first view controller is not working help me to solve this issue...Thanking you
You can use NotificationCenter to receive data.
On press of your Get Data button in your ThirdViewController, post your notification.
let myDataToPass : [String: Any] = ["myData" : yourStringValue]
NotificationCenter.default.post(name: Notification.Name("getDataPressed"), object: myDataToPass)
In your FirstViewController, add observer in viewDidLoad that will listen for the notification:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(receiveInitialDetails(notification:)), name: Notification.Name("getDataPressed"), object: nil)
}
//once the notification is received, this function will be called and you can get the data that you passed in thirdVC using notification.userInfo
#objc func receiveInitialDetails(notification : Notification) {
let data = notification.userInfo as! [String:Any]
let yourStringValue = data["myData"] as! String
// you have your data here. downcast it to your desired data type.
}
you can implement it by using notification center
below I give a small example how I pass imageDataDict in my project
let imageDataDict:[String: UIImage] = ["image": image]
// Post a notification
NSNotificationCenter.defaultCenter().postNotificationName(notificationName, object: nil, userInfo: imageDataDict)
// Register to receive notification in your class
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.showSpinningWheel(_:)), name: notificationName, object: nil)
// handle notification
func showSpinningWheel(notification: NSNotification) {
if let image = notification.userInfo?["image"] as? UIImage {
// do something with your image
}
}
You can save the third view controller data to UserDefaults. Get data from User Defaults at first View controller :
`UserDefaults.standard.set(yourData, forKey: "yourDataKey")` // at third view controller
`UserDefaults.standart.string(forKey: "yourDataKey")` //first view controller
Hope it helps...
Reason your code not working:
As soon as you move to second view controller , your third view controller is deallocated from memory. Below line has no meaning in first view controller
let vcThird = storyboard.instantiateViewController(withIdentifier: "third") as! ThirdViewController //third view
vcThird.thirddelegate = self
You move to second view controller , third view controller is set to nil.
Either you can use NSNotificationCenter to move data from third to first.
If you want to go with protocols, than make below code change.
Code : ViewController.swift
Remove the code:
let vcThird = storyboard.instantiateViewController(withIdentifier: "third") as! ThirdViewController //third view
vcThird.thirddelegate = self
ThirdViewController.swift
protocol thirdviewDelegate //delegate to pass data from thirs view to first view
{
func thirdView(datas:String)
}
class ThirdViewController: UIViewController {
var thirddelegate:thirdviewDelegate?
#IBOutlet var thirdTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func thirdViewInvoke(_ sender: Any) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let firstView = storyboard.instantiateViewController(withIdentifier: "first") as! ViewController //third view
self.thirddelegate = firstView
self.thirddelegate?.thirdView(datas: thirdTextField.text ?? "default value")
self.navigationController?.popToRootViewController(animated: true)
}
}
any help is appreciated.
I am new to Ios development and I am trying to change a label text which is located in my first initial view controller. I want this text to change as I press a button in the second view controller which is segued to the initial one.
here is my first view controller
import UIKit
protocol gameModeDelegate {
func didTapChoice(test:String)
}
class ViewController2: UIViewController {
var selectionDelegate:gameModeDelegate!
#IBAction func chooseButton(_ sender: Any) {
selectionDelegate.didTapChoice(test: "TEST")
let selectVC = storyboard?.instantiateViewController(withIdentifier: "VC1") as! ViewController
present(selectVC,animated: true,completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
here is what i have done in the second where the label is
override func viewDidLoad() {
super.viewDidLoad()
let selectVC2 = storyboard?.instantiateViewController(withIdentifier: "VC1") as! ViewController2
selectVC2.selectionDelegate = self
winningLabel.isHidden = true
winningLabel.center = CGPoint(x: winningLabel.center.x, y: winningLabel.center.y - 400)
playAgainoutlet.isHidden = true
playAgainoutlet.center = CGPoint(x: playAgainoutlet.center.x, y: playAgainoutlet.center.y + 400)
}
extension ViewController: gameModeDelegate{
func didTapChoice(test: String) {
CommunicationLabel.text = test
}
}
I tried these two methods so far and i keep getting this error.
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
You should not use this approach to achieve the result, you may use two different approaches to achieve the same result.
1- Use a delegate protocol approach:
in secondViewController you should declare a protocol like this
protocol applySelecction {
func applyText(text: String)
}
and in the class declare a variable like this.
var delegate: apply selection?
then in the button action
#IBAction func saveButtom(sender: UIButton){
//print(selected)
delegate?.applySelection(text: text) //text is the value select from UILAbel o the option the user select
self.dismiss(animated: true, completion: nil)
}
then in firstViewController conforms to applySelection protocol like this
class FirstViewController: UIViewController,applySelection{
func applyText(text: String){
//update the UIlabel here
2- Use a closure.
here in secondViewController you should add a new var like this,
var applyText: ((String) -> Void)?
then in
#IBAction func saveButtom(sender: UIButton){
self.applyText(text) //text is your text to update
}
and in firstViewController in prepare for segue rewrite like this.
let vc = segue.destination as! fisrtViewController)
vc.applyText = { [weak self] data in
guard let self = self else {return}
self.text = text //this is assigning the text to self-text supposing text is a UILabel in this viewController
}
You may try one of the two approaches which may seem right for you.
EDIT.
try this.
class ViewController2: UIViewController {
var selectionDelegate:gameModeDelegate!
#IBAction func chooseButton(_ sender: Any) {
selectionDelegate.didTapChoice(test: "TEST")
//if segue is a show segue
self.navigationController?.popViewController(animated: true)
//else is a modal segue.
dismiss(animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
PD. you dont have to present a viewcontroller already present in the view stack, only dissmis it. Good luck
There are 2 controllers.
this is how the UI looks
this is how I am creating the popup i.e. using segue
HomeViewController:
has a label and a button. upon click on this button named --> 'add action' --> a popup is opened.
PopupViewController:
is a popup where user can enter input and tap save. in the popup, there is a textfield. User fills the field and clicks save.
upon save --> an IBAction is called for this PopupViewController, which has dismiss() function to dismiss the popup.
and the completion block inside the dismiss function is where I am trying to instantiate HomeViewController to update the labels.
(Note: PopupViewController is created via segue, by selecting over the current context)
but while doing so, I see that, all the IBOutlets inside of HomeViewController are nil upon trying to save from popup, therefore I am not able to update the labels.
What I have tried:
I have checked other Q&A on web and verified below:
1. I have checked the connection of the label to the story board. it's correct.
2. I have used instantiateViewController syntax in order to instantiate
HomeViewController properly.
but still the problem persist.
HomeViewController
var actionNames = [String]()
var actionDescriptions = [String]()
#IBOutlet weak var firstActionLabel: UILabel!
func updateViewWithNewAction() {
print("updating views started")
if firstActionLabel != nil {
if actionNames.count > 0 {
firstActionLabel.text = actionNames[0]
} else {
print("no actions in the array")
}
} else {
print("firstActionLabel is nil")
}
print("updating views completed")
}
func addActions(actionName: String, actionDescription: String) {
actionNames.append(actionName)
actionDescriptions.append(actionDescription)
print("actions added")
}
PopupViewController
#IBOutlet weak var actionTitle: UITextField!
#IBOutlet weak var actionDescriptionTextView: UITextView!
#IBAction func createAction(_ sender: Any) {
//getting action values from user
actionName = actionTitle.text!
actionDescription = actionDescriptionTextView.text!
dismiss(animated: true, completion: {
print("completion block started ---")
let homeVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "HomeViewController") as! HomeViewController
homeVC.addActions(actionName: self.actionName, actionDescription: self.actionDescription)
homeVC.updateViewWithNewAction()
print("completion block ended ---")
})
}
Expected Result: upon createAction() of PopupViewController, the label inside HomeViewController should be updated with the new value.
Actual Result: firstActionLabel is nil, during homeVC.updateViewWithNewAction()
Basically I think you want something like this:
add in HomeViewController
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let popupViewController = segue.destination as? PopupViewController {
popupViewController.callback = self.addActions
}
}
And in PopupViewController add
var callback: ((String, String) -> Void)?
Then in PopupViewController change
#IBAction func createAction(_ sender: Any) {
//getting action values from user
actionName = actionTitle.text!
actionDescription = actionDescriptionTextView.text!
dismiss(animated: true, completion: {
callback?(self.actionName, self.actionDescription)
})
}
Do it like this
class HomeViewController: UIViewcontroller {
func viewDidLoad() {
super.viewDidLoad()
updateViewWithNewAction()
}
The problem is, until viewDidLoad, any of you IBOutlet won't be initialized. They are supposed to initialize in via storyboard. You cannot get any reference until viewDidLoad.
If you don't want to call updateViewWithNewAction() every time, then add a Bool flag to decide to call or not call updateViewWithNewAction(). Whenever needed set the Bool flag from PopUpViewController or any other places.
I have two UIViewController, when I click a button, it goes from the first view controller to the second one. And before that, I animated a UIView to move to another place. After dismissing the second View Controller, I want to move the UIView in the first view controller back to where it originally was. However, when I call a function from the second View Controller to animate the UIview in the first view controller after dismissing the second one, It could not get the UIView's properties, and cannot do anything with it. I think because the first UIViewController is not loaded yet. Is that the problem? And How should I solve this?
There are two solutions you can either use swift closures
class FirstViewController: UIViewController {
#IBAction func start(_ sender: Any) {
guard let secondController = self.storyboard?.instantiateViewController(withIdentifier: "SecondController") as? SecondController else { return }
secondController.callbackClosure = { [weak self] in
print("Do your stuff")
}
self.navigationController?.pushViewController(secondController, animated: true)
}
}
//----------------------------
class SecondController: UIViewController {
var callbackClosure: ((Void) -> Void)?
override func viewWillDisappear(_ animated: Bool) {
callbackClosure?()
}
}
or you can use protocols
class FirstViewController: UIViewController {
#IBAction func start(_ sender: Any) {
guard let secondController = self.storyboard?.instantiateViewController(withIdentifier: "SecondController") as? SecondController else { return }
secondController.delegate = self
self.navigationController?.pushViewController(secondController, animated: true)
}
}
extension ViewController : ViewControllerSecDelegate {
func didBackButtonPressed(){
print("Do your stuff")
}
}
//--------------------------
protocol SecondControllerDelegate : NSObjectProtocol {
func didBackButtonPressed()
}
class SecondController: UIViewController {
weak var delegate: SecondControllerDelegate?
override func viewWillDisappear(_ animated: Bool) {
delegate?.didBackButtonPressed()
}
}
You can try to use a closure. Something like this:
class FirstViewController: UIViewController {
#IBOutlet weak var nextControllerButton: UIButton!
private let animatableView: UIView = UIView()
private func methodsForSomeAnimation() {
/*
perform some animation with 'animatableView'
*/
}
#IBAction func nextControllerButtonAction() {
// you can choose any other way to initialize controller :)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
guard let secondController = storyboard.instantiateViewController(withIdentifier: "SecondViewController") as? SecondViewController else { return }
secondController.callbackClosure = { [weak self] in
self?.methodsForSomeAnimation()
}
present(secondController, animated: true, completion: nil)
}
}
class SecondViewController: UIViewController {
#IBOutlet weak var dismissButton: UIButton!
var callbackClosure: ((Void) -> Void)?
#IBAction func dismissButtonAction() {
callbackClosure?()
dismiss(animated: true, completion: nil)
/*
or you call 'callbackClosure' in dismiss completion
dismiss(animated: true) { [weak self] in
self?.callbackClosure?()
}
*/
}
}
When you present your second view controller you can pass an instance of the first view controller.
The second VC could hold an instance of the first VC like such:
weak var firstViewController: NameOfController?
then when your presenting the second VC make sure you set the value so it's not nil like so:
firstViewController = self
After you've done this you'll be able to access that viewControllers functions.
iOS 11.x Swift 4.0
In calling VC you put this code ...
private struct Constants {
static let ScannerViewController = "Scan VC"
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == Constants.ScannerViewController {
let svc = destination as? ScannerViewController
svc?.firstViewController = self
}
}
Where you have named the segue in my case "Scan VC", this is what it looks like in Xcode panel.
Now in scan VC we got this just under the class declaration
weak var firstViewController: HiddingViewController?
Now later in your code, when your ready to return I simply set my concerned variables in my firstViewController like this ...
self.firstViewController?.globalUUID = code
Which I have setup in the HiddingViewController like this ...
var globalUUID: String? {
didSet {
startScanning()
}
}
So basically when I close the scanning VC I set the variable globalUUID which in term starts the scanning method here.
When you are saying it could not get the UIView's properties it's because you put it as private ? Why you don't replace your UIView in the first controller when it disappears before to go to your secondViewController. I think it's a case where you have to clean up your view controller state before to go further to your second view controller.
Check IOS lifecycle methods : viewWillDisappear or viewDidDisappear through Apple documentation and just do your animation in one of these methods.
Very simple solution actually... Just put your animation in the viewDidAppear method. This method is called every time the view loads.
class firstViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// insert animation here to run when FirstViewController appears...
}
}