Xcode Storyboard workflow loop - ios

I've set up a storyboard which has in it a loop. I start with the form view, the user signs and after that it goes back to home. From home you can do a form entry again. So this goes on and on. Does this affect the memory when I have more than 40 UIViews in my stack of navigation Controller? If yes, how can I jump back to the home screen after the user signed up? Or how can I close the Views which were used in the past?

https://developer.apple.com/library/ios/referencelibrary/GettingStarted/RoadMapiOS/FirstTutorial.html
is the very first iOS tutorial and explains how to do exactly that: Two storyboards, and going forth and back between them. You'll always be using the same views really. Unless you do it all by hand and push forty storyboards on the stack.

Related

Deep linking into a storyboard with the correct backstack

I would like to create a "deep link" into my storyboard while preserving the backstack (back button navigation).
Ex:
Given the storyboard below (entry point being the leftmost Navigation controller)
When my application is opened via a remote notification I would like to open the second tab in by tab controller AND be able to navigate back to the item list via the back button.
Please note that I am not asking about how to open the second tab, or how to create such a storyboard but specifically if there is a way to do this with storyboards or will I have to do it by code.
Thanks!
PS: I come from an Android background where one recreates the parent view controller manually or (better) inserts it into the backstack. As far as my research goes there is no such thing in ios. I'm hoping I'm wrong.
Your UINavigationController has a viewControllers property. You can create as many view controllers as you want in an NSArray and assign it to this property and that will be the back stack with the last VC in the array displayed.
The problem is that when a notification arrives, your app could be in any state at all. It could be running, with some other screen showing. It could be suspended, with some other screen showing. Or it might not be running at all, and will now have to be launched from scratch.
Thus, starting in the App Delegate routine that responds here, you will have to deal manually (in code) with the situation if you want to put your app into an appropriate state.

What's causing this memory leak?

The Problem
I'm currently building an iPad game using SpriteKit. The gameplay is driven by sound provided by EZAudio. After running the Instrumentation tools to profile my app, I noticed that whenever the GameViewController is shown memory allocation jumps up. When I repeatedly show the screen (5+ times) it crashes the app. My project uses ARC.
Navigation
The navigation consists of 4 ViewControllers:
MenuViewController: This shows the menu
CharacterSelectionViewController: It lets you a pick a character to use
GameViewController: This lets you play a game with the player chosen
ScoreViewController: It shows you the score you achieved in the game
1 - MenuViewController
From here you can navigate to CharacterSelectionViewController via a Show (e.g. Push) segue.
2 - CharacterSelectionViewController
You can navigate to GameViewController via a Show (e.g. Push) segue. There is also a back button that goes back to MenuViewController with the following code:
[self.navigationController popViewControllerAnimated:YES];
3 - GameViewController
It first shows a 5 second countdown (using NSTimer)
The game starts with the character chosen in CharacterSelectionViewController
The game can be paused, allowing you to quit and go back to MenuViewController via a manual Show Detail (e.g. Replace) segue.
When the game ends, a manual Show (e.g. Push) segue is called that navigates to the ScoreViewController.
It's view hierarchy consists of three sets of view - one for the countdown, one for the pause menu and one for the game. These are subsequently shown/hidden. See the view hierarchy below:
4 - ScoreViewController
This allows you to quit or restart the game. When quit it pressed it performs a Show Detail (e.g. Replace) segue to MenuViewController. If restart is pressed it performs an unwind to CharacterSelectionViewController.
Responses
Please provide answers regarding:
How this kind of leak could occur
Any observations you have from the allocation and leaks screenshots
Allocation
Below, you can see the increasing allocations as I cycle through the apps screens to repeatedly show the GameViewController. I used Mark Generation to be able to show the increase in memory allocations.
Leaks
Here you can see the memory leak that occurred. This is ordered by size.
Ignore the leaks for the moment; fix the generational accretion first.
Is that generation snapshot representative of what is left after a typical snapshot? Typically, you'd want to show view controller, take snapshot, hide then show view controller, take snapshot, etc... as many times as you can without crashing (or 10 times if it doesn't crash).
Then look at generation 3 or 4 as that'll be the most stable representation of per-generation accretion.
If it is representative, it looks like you are leaking everything that the view controller would normally allocate. Ultimately, you are looking for the "root" of your object graph that is keeping everything around. Fix the reason why the root is sticking around and the rest'll likely go away.
I wrote a weblog post about this. It is a bit outdated, but the analysis workflow remains the same.
http://www.friday.com/bbum/2010/10/17/when-is-a-leak-not-a-leak-using-heapshot-analysis-to-find-undesirable-memory-growth/
How are you unwinding from your various view controllers? I note that you mention that when the game ends you're pushing another VC onto the stack, but I presume this VC chain will at some point unwind back to your initial menu? (In essence, I wonder if you're just looping around, hence adding new VCs to the stack everytime you play a game.)
To create an un-wind segue, simply create an empty method in the destination VC (i.e.: your main menu) as such:
- (IBAction)unwindToMainMenu:(UIStoryboardSegue*)sender
{
// Intentional NOP
}
(N.B.: Make sure it's also listed in the header.)
You can then call this as you would any other segue in your storyboard by dragging from the source object in question to the exit option at the top of the VC that contains the source object in the storyboard. This will present you with a list of segues to choose from. (You can verify that the segue is setup correctly by selecting the source object in the storyboard - the Connections inspector should list the unwind segue within the Triggered Segues section.)

iOs: at Launch, segue to a specified viewcontroller

I am hoping for a quick tip or strategy on this problem and see how you have or would solve this.
At launch, I am checking for the user "status." This basically means:
1. Check if they have a session in progress aka.. they are logged in
2. Check if they have entered in a Credit Card yet
3. Check if they have clicked on a confirmation email
Based on whether these statuses are true or not, I want to segue at launch to the appropriate viewcontroller (ex: if no CC detected, segue to a credit card entry page ... etc).
Currently, my iOS8 setup is as follows:
1. Checking user "status" in didFinishLaunchingWithOptions: in the appdelegate
2. I have a launch screen xib that (as far as I know) cannot have a viewcontroller attached (therefore I cannot segue at that point which would be most ideal).
Does anyone know a way to tackle this problem?
Thanks!
I presume you are using a storyboard. That's part of the problem here, but it is not insuperable. By the time your code in didFinishLaunching... runs, you already have a window and that window has a root view controller. Thus you can get a reference to that root view controller and do any pushing or presenting of a different view controller on top of it. And since you are doing this before the interface is shown, your interface will appear with the desired view controller showing.
But be careful not to do anything time-consuming. I don't know what all this "checking" involves but if it takes any time, the watchdog will kill your app dead for taking too long to launch. It is better to launch into your root view controller and then do your checking - even if this means the user will see the root view controller for a while. Just design a root view controller that is okay to show.

iOS How to implement a countdown screen before the user sees the view

I was wondering what is the best way to implement a countdown screen before showing the user the game view. For a more detailed example, I want the user to see a screen that displays 3...2...1...GO ! and than the game will appear.
Currently in my application I am using a navigation controller as my main menu where you can select multiple games to choose from. When a user selects one of the game buttons this is where I want the countdown screen to appear before my game interfaces does.
Solutions that I have thought about:
1) should I implement a new view controller that i push on the navigation controller to perform the count down ( seems like a waste)
2) is there a way to blank everything on a view and show a countdown first?
Thanks in advance for your help and cooperation !
Ryan
The best way i think is as soon as user selects a game, add your 3..2..1. Go screen on the same view..as soon as u present this u can also start preparing to create your game interface(but do not present). After GO appears, remove this countdown view and present your game..
It depends on the effect you are after. If you push a view controller onto the navigation stack, you'll need to use a pop transition.
My suggestion would be to open the game view controller and put a full-screen sized overlay view on top of it with your countdown message. Have the game VC manage the countdown view. When the countdown is complete, you could fade it, shrink it to a point, do some sort of clock wipe or keyhole animation, or whatever you want, easily and simply. (Some things are obviously easier than others. Cross-fades, shrinks and the like are trivial. clock wipes and keyhole transitions are much harder and require pretty advanced Core Animation skills.
What platform will this be for? For a full screen overlay I would try UIPopoverViewController if on an iPad. Otherwise, try a view controller presented modally. I believe you can set the transparency of either type to less than 1 so the underlying view shows through. In this case it would be nice to display the selected game's opening screen during the countdown. Of course it would be dark because of the overlying view. But it would provide a glimpse into what is to come.

How to handle jumping back to previous screens in iOS

I am just looking for a sanity check here.
I have a screen that the user passes through on the way into the main application. That screen can be navigated back to from almost anywhere in the system.
As it stands I am just presenting ViewControllers without using a NavController to manage them (it does not seem applicable for most of my app, since screens are not necessarily sequential or related to one another).
My question is, if I have presented VC1, then navigate to other screens, and finally want to present VC1 again, I am doing something like:
[self presentViewController:[self.storyboard instantiateViewControllerWithIdentifier:#"VC1"] animated:YES completion:nil];
Is this bad form? Am I leaking memory by creating a bunch of VC1 instances or is there some magic that uses the previously created one?
If it is bad form, how do I get back to the original VC1 to reuse it?
Thanks for any input.
I think you pegged it: It's not a great idea to have multiple instances of the same view controller in memory at the same time. Every time you instantiate a new view controller and present it modally, you'll consume more memory.
The most elegant solution is the iOS 6 unwind segue. But most of us would be unwilling to give up on iOS 5 support quite yet.
If you need to support iOS 5, you could contemplate using navigation controller, but hide the navigation bar if you don't like it in your user interface. Then replace modal segues with push segues and now you can do popToRootViewController whenever you want to return to the main view controller.

Resources