Transition to Root View Controller - swift

I've tried literally countless and various ways to back to my initial viewController but I can't get anything to work. If any of you guys can see what i'm doing wrong I would be incredibly happy.
Just to make sure I have a print statement in every scene and every viewcontroller and initially the rootviewcontroller print statement does work but I know it's not fully transitioning over since the print statement isn't happening again.
Below is a snippet of the transition code and below that a picture of my storyboard:
func menu()
{
self.view?.presentScene(nil)
//let theVC = self.viewController?.storyboard?.instantiateViewController(withIdentifier: "menuVC") as! MenuVC?
//self.viewController?.navigationController?.pushViewController(theVC!, animated: true)
self.viewController?.dismiss(animated: false, completion: nil)
self.viewController?.navigationController?.popToRootViewController(animated: true)
print("LastScene")
}

Related

How do I end a game once a condition has been met?

I'm making a battleship game on Xcode 11 using Storyboards, and I've pretty much done everything except a Game Over screen and stop registering the guesses once the counter reaches 0. This is also my first time making a game on my own. Here's one of the IBActions I made for the buttons:
#IBAction func square1Button(_ sender: Any) {
if randomNum == 1 {
square1.image = UIImage(named: "ShipPatrolHull")
} else {
guesses -= 1
Turns.text = String(guesses)
if guesses == 0 {
}
}
}
The if statement in the else statement is empty because I don't know what to add there to make the variable guesses stop going down and to make a Game Over screen to show. I've also added a Storyboard called GameOver and is linked back to the main storyboard.
You could display a Game Over UIAlertController and then have the game reset when they select "Play Again." However, you mention that you already have another Storyboard for a separate Game Over screen. All you need to do is present that Game Over view controller. Make sure to set the storyboard identifier for the view controller you are trying to present so you can access it in code. See below for guidance,
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = self.storyboard.instantiateViewController(withIdentifier: "GameOverView")
From here you can easily present it.
self.present(controller, animated: true, completion: nil)
Lastly, to make the guesses stop going down, reorganize your if-statements in order to only subtract one from the guesses if the guesses value is not equal to zero, otherwise... game over.
if guesses != 0 {
Turns.text = String(guesses)
guesses -= 1
} else {
//Game over, reset, etc.
}

Present below current view and not above

I'm trying to present a view controller below another presented view controller (like WhatsApp when you open camera and press gallery).
I tried many things but none worked ..
Use child view controller and set view of that added child view controller at the top of hierarchy. It will be top most element, so actual background of this view will be obscured, but that's the way to go.
//code inside UIViewController class
func addViewControllerAtBottom() {
let newVC = NewVCType() //just instantiate it
addChildViewController(newVC)
view.insertSubview(newVC.view, at: 0) //at 0 means it's first rendered, all others will be on top of it
}
You can reproduce this behavior by doing the following :
First, create a NavigationController with a root ViewController :
let navController = UINavigationController(rootViewController: firstController)
Then, present this navigationController with animated: false and in the completion of the present method, push your second ViewController, still with animated: false (to avoid weird animations) :
present(navController, animated: false) {
navController.pushViewController(secondController, animated: false)
}
Here you go, you got a new navigation with 2 UIViewController, like WhatsApp.
Full code, wrapped into a button's action :
#IBAction func buttonTapped(_ sender: Any) {
let navController = UINavigationController(rootViewController: firstController)
present(navController, animated: false) {
navController.pushViewController(secondController, animated: false)
}
}

Eureka: How to push a VC from a PushRow without Segue

I am using Eureka to do a settingsVC and I am having trouble pushing a newVC from a pushRow. Note that I do not use storyboard
My setup is relatively simple, and my newVC is a simple UIViewController with some uitextfields and labels. Because I do not use storyboard, I can't seem to use performSegues and $0.presentationMode = .segueName(segueName: "RowsExampleViewControllerSegue", onDismiss: nil)
I have also reviewed this post but this post is relatively far fetched for my application.
My implementation so far as such:
class AccountsViewController: FormViewController {
override func viewDidLoad() {
super.viewDidLoad()
form +++ Section("Profile")
<<< PushRow<String>() { row in
row.title = "Edit phone number"
row.value = "+61 12345678"
}.onCellSelection({ (cell, row) in
self.navigationController?.pushViewController(ChangePhoneNumberViewController(), animated: true)
})
The above approach pushes the VC twice.
My reason for wanting to adopt pushRow is because I want it to adopt the pushRow aesthetic looks, like the image attached. I have also considered exploring ButtonRow but the UI/UX is just not right. Moving ahead I would also need to use protocols to bring the new "phoneNumber" to the AccountsViewController.
EDIT:
Attempted the following code but produces the error message.
I was having the same error, you can try to include the return type and also the argument label builder to the callback:
row.presentationMode = PresentationMode.show(
controllerProvider: ControllerProvider.callback(builder: { () -> UIViewController in
return AcknowListViewController()
}),
onDismiss: nil)
I think you just need to set the presentation mode like this:
presentationMode = PresentationMode.show(
controllerProvider: ControllerProvider.callback(
{return ChangePhoneNumberViewController()}
), onDismiss: nil)
ControllerProvider.callback lets you provide a VC by returning one from a closure, instead of from a nib file or storyboard.

How do I segueing to the UIViewController I'm in?

I'm trying to go from one view, filled with data from an object, to the same view but filled with a different object via segue.
Using a segue is necessary as apposed to switching the object and refreshing the view because my users need to be able to go back to the past view controller when they hit the back button.
Example:
(ThisView, with thisObject populating the view) -> (ThisView, with thisOtherObject populating the view)
What I've tried:
presentView Controller: This didn't work because it is not the default segue I'm trying to achieve.
let next: NewClubProfile = storyboard?.instantiateViewControllerWithIdentifier("clubProfile") as! NewClubProfile
presentViewController(next, animated: true, completion: nil)
Using Navigation Controller: Can't figure out how to segue the new object to populate the other view
let next: NewClubProfile = storyboard?.instantiateViewControllerWithIdentifier("clubProfile") as! NewClubProfile
self.navigationController?.pushViewController(next, animated:true)
Should have taken longer to solve this myself before posting this but I couldn't find an answer that fit what I needed. Anyway, solved it, here's what worked for me.
let next: ViewController = storyboard?.instantiateViewControllerWithIdentifier("viewName") as! ViewController
next.object = newObject
self.navigationController?.pushViewController(next, animated:true)

Warning: Attempt to present view controller on another view controller whose view is not in the window hierarchy

I have a working simple single player game, where the initial view controller has a button to start the game. This button performs a segue and all game logic in the GameViewController is working as expected.
I've followed this tutorial to add multi player functionality to my game.
On the initial view controller, a button now calls
GameKitHelper.sharedGameKitHelper.findMatchWithMinPlayers(2, maxPlayers: 2, viewController: self, delegate: MultiPlayerNetworking)
}
which has the following implementation in GameKitHelper.swift:
func findMatchWithMinPlayers (minPlayers: Int, maxPlayers: Int, viewController: UIViewController, delegate: GameKitHelperDelegate) {
matchStarted = false
let request = GKMatchRequest()
self.delegate = delegate
request.minPlayers = 2
request.maxPlayers = 2
presentingViewController = viewController
presentingViewController.dismissViewControllerAnimated(false, completion: nil)
let mmvc = GKMatchmakerViewController(matchRequest: request)
mmvc?.matchmakerDelegate = self
presentingViewController.presentViewController(mmvc!, animated: true, completion: nil)
self.delegate?.matchStarted()
}
The Class MultiPlayerNetworking implements the GameKitHelper protocol, and gets called on the matchStarted function.
The MultiPlayerNetworking class in essence takes over here, and starts sending out messages to hosts and remote players.
Note that some time later, When auto-matching finishes, the following function gets called in GameKitHelper:
func matchmakerViewController(viewController: GKMatchmakerViewController, didFindMatch match: GKMatch) {
viewcontroller.dismissViewControllerAnimated(true, completion: {})
self.match = match
match.delegate = self
}
Now, I think this says that the GKMatchmakerViewController is dismissed, thereby showing me the initial view controller again (and this is what happens on screen).
Now my issue! After the GKMatchmakerViewController is dismissed, I'm back at the initial view controller and want to 'simulate' an automatic segue to my gameView (which has logic to deal with a multi player game as well).
I've made the initial view controller conform to the MultiPlayerNetworking protocol, which has a function to simulate a segue:
func segueToGVC() {
self.performSegueWithIdentifier("game", sender: nil) // self = initial view controller
}
However, xCode complains with:
Warning: Attempt to present <GameViewController: 0x7d440050> on <GKMatchmakerViewController: 0x7c8fbc00> whose view is not in the window hierarchy!
I'm stuck here, and have tried so many different methods of dismissing the view controller, to making sure I'm calling the performSegue function on the topViewController via this link, but nothing works.
My question: why is the GKMatchmakerViewController visually dismissed, but still present in the view hierarchy, such that calling a performSegue function on the initial view controller give the above error/warning?
Views are greatly appreciated!
why is the GKMatchmakerViewController visually dismissed, but still present in the view hierarchy
Here are two suggestions:
Perhaps it's because dismissal takes time. You are saying:
viewcontroller.dismissViewControllerAnimated(true, completion: {})
So there's an animation. Don't attempt to perform the next segue until the animation is over.
Perhaps you are just wrong about who self is. You are saying:
self.performSegueWithIdentifier("game", sender: nil)
// self = initial view controller
We have only your word, in that comment, for who self is. Meanwhile, the runtime seems to think differently about the matter:
Attempt to present <GameViewController: 0x7d440050> on <GKMatchmakerViewController: 0x7c8fbc00>
It might be good to believe the runtime; after all, it knows more than you do.