1

Long story short, my segue could not be performed to my next controller which i have already created. Much help will be appreciated.

    override func viewDidLoad() {
        super.viewDidLoad()


        var returnValue: Int = UserDefaults.standard.integer(forKey: "quiz1Validation")
        if (returnValue == 1)
        {
            performSegue(withIdentifier: "completed", sender: self)
        }
        else {
        var returnValue: Int = UserDefaults.standard.integer(forKey: "userScore")
        scorelabel.text = "Score:\(returnValue)"
        RandomQuestions()
    }

}
Owen Pauling
  • 11,349
  • 20
  • 53
  • 64
Kinja
  • 449
  • 5
  • 22
  • 2
    What is the error? – Grady Aug 01 '17 at 18:33
  • Have you created the segue in storyboard from your current VC to new one. Also is the identifier correct? – Kapil G Aug 01 '17 at 18:34
  • Yes I have alrdy done all that you have stated, I think it's because I can't load it in viewdidload – Kinja Aug 01 '17 at 18:36
  • Check this: segue with this identifier must exist, the segue must start from this view controller. If after checking this it doesn’t work, give a bit information – antonsergeev88 Aug 01 '17 at 18:38
  • Why would you even call a segue from either `viewDidLoad` or `viewWillAppear`? It makes no sense, since in this case the `ViewController` you are calling the segue from might not even be displayed at all, in which case you could have called the segue from the previous VC. – Dávid Pásztor Aug 01 '17 at 18:41
  • @Kinja try move this logic into viewDidAppear as suggested below – antonsergeev88 Aug 01 '17 at 18:45
  • performing a segue from a view which is not even in the navigation stack yet? I'm not sure your concept behind the idea, but that is not supposed to work on a nested way; try to invoke the method _after_ your view is in the navigation stack and the previous segue has done. – holex Aug 02 '17 at 09:30

4 Answers4

6

You cannot call performSeugue from viewDidLoad. You have to call it from viewDidAppear.

Martin Muldoon
  • 3,388
  • 4
  • 24
  • 55
0

Performing a segue on viewDidLoad is not recommended as your viewController is not yet on the stack.

As work around you can try this, but I would change the logic to not use it:

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
    performSegue(withIdentifier: "completed", sender: self)
}
GIJOW
  • 2,307
  • 1
  • 17
  • 37
  • 1
    I would seriously discourage anyone from using such a workaround. You have no idea how much time passes between the system calling `viewDidLoad` and `viewWillAppear`. – Dávid Pásztor Aug 01 '17 at 18:40
  • and what's the relation between with this WA ? You just need to have your view in the stack, behaviour of threads will be exactly the same. You don't need to have thread flag from viewWillAppear to call another VC. In any case, I stated in the answer to change the logic to not use it. – GIJOW Aug 01 '17 at 18:43
  • Thanks guys but apparently the view controller still opens for a mere second before it performs a segue to another view controller, is there a way to skip the view controller and immediately jump to the view controller which i want to segue to? – Kinja Aug 01 '17 at 19:01
  • @Kinja in your story board check the check box for initial view controller on the view you want to start – Steve Aug 01 '17 at 19:02
  • Ermm but I don't want that view controller to be the start of app view page – Kinja Aug 01 '17 at 19:14
  • Is this your first viewcontroller ? If so, best approach is to use `@UIApplicationMain` in your `AppDelegate.swift` and handle your viewcontroller calls via code. Not segues. – GIJOW Aug 01 '17 at 19:18
  • Nope unfortunately it isn't :(, is there another approach? – Kinja Aug 02 '17 at 01:48
  • it's ok, i already managed to do it thanks for taking your time to help me! – Kinja Aug 02 '17 at 13:19
0

I think mostly probably @Kinja was trying to skip a particular view controller here base on a particular state ( archived in user defaults )by try calling performSegue in the viewDidLoad method itself.

So I would recommend to try below approach instead of doing performSegue-

How to load all view controllers storyboard, but skip the natural sequence and go direct to a specific view?

Hope this will help.

I made a sample code to demo the same @

git clone https://shreekara@bitbucket.org/shreekara/viewcontrollers.git

Check how 2 view controllers are directly populated

let storyboard = UIStoryboard(name: "Main", bundle: nil)

let viewcontroller2 = storyboard.instantiateViewController(withIdentifier: "view2")
self.navigationController?.pushViewController(viewcontroller2, animated:false)

let viewcontroller3 = storyboard.instantiateViewController(withIdentifier: "view3")
self.navigationController?.pushViewController(viewcontroller3, animated:false)
Shreekara
  • 149
  • 2
  • 8
  • yes you are totally right, apparently performing a segue will still open the particular controller first before segue-ing to another controller which i really do not want. do you know how to resolve this? or this hyperlink is the exact way? – Kinja Aug 01 '17 at 18:56
  • @Kinja The above link pretty much explains the same. Since you have to load a given view controller programmatically based on some state you have to follow the same approach. Made a sample project to demo the same. Please check @ https://shreekara@bitbucket.org/shreekara/viewcontrollers.git – Shreekara Aug 02 '17 at 07:58
  • ermm i can't seem to go to ur link. – Kinja Aug 02 '17 at 13:06
  • it's ok bro, i already managed to do it, Thanks for taking your time to help me! – Kinja Aug 02 '17 at 13:20
0

The way I seem to be forced to handle this is to create an @objc selector, and then call that from viewDidLoad() with perform(). Only seems to work with the "afterDelay" version:

@objc func showCompleted() {
  self.performSegue(withIdentifier: "completed", sender: self)
}

override func viewDidLoad() {
  super.viewDidLoad()
  var returnValue: Int = UserDefaults.standard.integer(forKey: "quiz1Validation")
  if returnValue == 1 {
    self.perform(#selector(self.showCompleted), with: nil, afterDelay: 0)
  }
  else {
    // ...the rest of your code
  }
}

Seems like a hack to me, so I would love to hear if anyone else has solved this in a more "Swifty" way.