Swift - Deallocate previous view controller after segue - swift

I'm trying to find a proper way to handle my scene/view process flow in my game. I'm currently able to transition from a main menu to a game level, exit the game level and return to the main menu, but it's not deallocating any of the memory from any of the views.
I saw a lot of suggestions to use a UINavigationController to handle my view controllers. After trying that for a while, my current storyboard looks like this:
My root view controller is Menu View Controller. I first start in Title View Controller, segue to Menu View Controller, then segue to and from Game View Controller, but this is obviously not deallocating any of my memory.
My segues are done from within SKScenes using the following:
self.viewController?.performSegueWithIdentifier("segueName", sender: viewController)
where viewController is a var within the SKScene referencing its parent view controller.
Is there something I could try to get my process flow to work out? I just want to be able to traverse a title scene for login and server connections, then spend the rest of the time switching between a menu scene and some sort of game scene.
I've tried to implement a few suggestions, for example, dismissViewControllerAnimated(true, completion: nil) but none of them seem to be actually deallocating anything. The game slows to a crawl after just 2-3 cycles between the menu scene and game scene.
I've seen quite a few questions similar to this, but I've been so far unable to come up with a solution that works for me. I'm writing a game in Swift and Xcode 7.3.1.

I solved my issue. I ended up having a bunch of strong references to various things like my view, scene, and view controller. I had ~200 strong references in total, so I have a lot of cleaning up to do.
To find my strong references, I followed a guide on how to use Allocation Instruments in Xcode here: https://www.raywenderlich.com/97886/instruments-tutorial-with-swift-getting-started
Anyone with this same issue, check out this question: In swift, how to get memory back to normal after an SKScene is removed?
That's what helped me fix my issue.

So you've looked at a number of different approaches but most aren't appropriate for you and / or have been applied incorrectly.
You now have an unused navigation controller in your app. In general I would use a navigate controller, but it should be marked as the initial view controller and your current initial view controller should be the nav controllers root view controller.
Once you have that, you need to look into unwinding segues (or use a little code). At the moment you're just always showing new view controller instances, you're never going back. This is why you start having issues. You need to unwind from the game scene to the menu instead of showing a new menu.
That can also be done with code by telling the nav controller to pop the top view controller off its stack.

Related

Present one of active child view controllers fullscreen

I have a main viewController containing three separate childViewControllers. I would like to present one of them fullscreen after tapping, but I could not find any elegant way to present an already active viewController.
Would you propose any ideas on how to make such transition?
Is there a way to reuse the childViewController without creating new instance?
Without seeing any screenshots, I would recommend changing the main view controller to be its own view controller (maybe with buttons and views separating it into 3 sections), and then after clicking a button -> go to childViewController.
I've found that for easy transitions like this, the Hero cocoapod is super easy to use and UI friendly.
Check out the Hero cocoa pod here
Good luck!

NSViewController not released

I have a question on the ownership of windows vs view controllers and when they're released. I created a test project, and only added one line of code to the NSViewController:
deinit { print("ViewController Dismissed.") }
Why isn't this called when I close the window? I profiled it in Instruments and there aren't any memory leaks, but there is a reference to the ViewController still.
Also, I tried the "Release when closed" option on the NSWindow, still no dice. Can anyone help with understanding this? Thanks!!
I would have simply put this as a comment, but I don't have enough reputation:
Could there be a closure in your view controller that is maintaining a strong reference to your view controller or some object in your controller? That is one way a retain cycle can be created. If that was it, I would think it would show up in instruments, but it's just a thought.
Also, is your view controller part of any kind of larger navigation system, such as a tab bar controller? That could be a factor. I'm not sure.
As I know your running app always have the strong reference to a window instance, which in turn has the reference to a view controller. If you go to the Debug View Hierarchy after closing your window, you'll still see it there.If you remove storyboard entry point to that window in your storyboard, you wont have that window at all.

iOS Storyboard Modal Segues and Memory

My apps "short" description:
Basically an interactive storybook, I have a class that sets up a audio session and audio player which every other class(ViewControllers) in my app imports and calls a function or two to set the right sound to be played each time something happens(for instance.. user reads the story). Each ViewController has it's own .m and .h classes and uses them for animations and action handling. My app is only about 60 mb's in size (audio/images/code).
Now these ViewControllers are set up in a storyboard (they are 13 now) and are modal segued from one to the next one and then programmatically dismissed to go back.
When I run my app on my iPad now, I'm starting to get memory warnings and yes Instruments is showing me that my app is adding roughly about 40 Mb's for every ViewController that I segue to.
My questions are:
Do they reside in real memory no matter what I do? (I thought I wasn't holding any strong pointers to these view controllers).
Is there an easy way for me to dismiss one controller and still use a modal segue to get to the next one?(ran into troubles trying this)
Modal Segues are probably not the way I should be doing things in my App are they?!. They looked so nice and easy for my "storybook", but now they are giving me a very rough time.
Any other tips you can give me from what I described are appreciated.
Thank you.
Yes, as long as you present it modally. The presenter view controller keeps a strong pointer to the presented view controller. What you could do here is in the viewWillDisappear: release all the images and other views that might use memory !
You could instantiate your view controller using the method instantiateViewControllerWithIdentifier: and then presentViewController:animated:completion: like you would do with any view controller
It's up to you to decide. But you could easily mimic the animation if you wanted to.
If I understood everything correctly I would go with a singleton class kinda like 'AudioEngine' which is accessible from anywhere in any class. Then I would design all my viewcontrollers in my storyboard like you did. When I need to present modally another view controller, I'll do it using the answer of your 2nd question. If I still had a memory issue, I would try to cheat and keeps always 3 view controllers (like we do with the UIScrollView's infinite scroll) that I would reuse and I'll mimic the modal presentation using UIView's animation blocks.

Storyboard+Modal Segue + Memory

I have a storyboard with 6 View Controllers and their respective views. I do NOT have any navigation controllers associated with these 6 View Controllers.
To go from one view controller to another, the swipe gesture recognizer is used alongside a modal segue. All view controllers have alteast 1, and sometimes even two swipe gesture based modal segues to other view controllers.
My question is, do I need to worry about memory? When I swipe are these viewcontrollers going to be infinitely added to memory eventually causing the app to crash?
An example could be: Say I am in the first VC and I swipe Right to the second VC, then swipe once again to Right to Third VC, then swipe left twice to get back to the First VC will the memory contain this:
Memory: First VC, Second VC, Third VC, Another Copy of Second VC, Another copy of First VC?
I know it seems like a stupid question but since I have only started programming a couple days ago I am very worried I will be having memory issues.
I would appreciate your thoughts and any potentially helpful links to places that dicusses this issue.
you have a good question and it depends on how you are creating and dismissing your view controllers. Normally a design like you mentioned would be built using a built in controller like UINavigationController or UIPageViewController or maybe using a scrollview.
If you are "presenting" new view controllers, then you need to dismiss to remove them. If your not dismissing, then you view controllers will stick around.
If you are using segue's, remember that each segue creates a new instance.
If your logic generally says - swipe right: new modal segue, swipe left: dismiss, then you will be cleaning up as you go. This works if its ok that each right swipe creates a new instance.
If you need the six view controllers to stay in memory all the time, you may want to look at using a pageViewController or roll you own solution. I have seen some nice solutions like you describe using a scroll view.
If you wanted to use a scroll view, basically you would crete an array, load the array with the six instances of your view controllers, then load the scroll view for horizontal scrolling. Add the gesture recognizers and logic for left/right swipes and you have a nice horizontal page scroller.
Here is a very nice reference and tutorial that seems to solve the solution you are describing. http://www.wannabegeek.com/?p=168
good luck and happy new year.
As long as you dont keep strong references to the view (or its subviews, like buttons...), they will be deallocated if needed.

View controller/NIB architecture for non-navigation application with transitions?

I'm tinkering with an iPad app that (like many iPad apps) doesn't use the UINavigation root view control system, so I don't have natural ownership for each app "view". I essentially have two basic views: a document list view, and a document edit view.
I'm playing with UIView animation for getting from a selected document to the edit view.
I also have a toolbar on top that exists (with different buttons) in both "views".
Because I don't have UINavigation running the show for me, I have a tendency to just throw more and more stuff into one NIB and one view controller that owns the whole container. But now I'm trying to figure out how to segue from the document list view to the edit view if the edit view lives inside a different NIB, preserving the toolbar too.
Anyone have thoughts or experience on app structures like this? I find the docs lacking on best practices around code/UI structure for anything except trivial one-screen apps or full-on navigation apps.
You're not "supposed" to have parent/child view controllers owning subcomponents of the same "screen" according to the docs, but this implies one massive honking view controller that basically contains the whole app, and that can't be right.
Not sure if there's a "right answer" to this; I'm looking for some intelligent examples or suggestions. Nobody's touched this question in months, so I'm adding a bounty to generate good chatter. :)
Thanks!
UPDATE: I'm not talking about a split view, which is clearly well handled by a split view controller. Instead, take a look at Apple's iWork apps (e.g. Pages) which have a document list view and an independent edit view, but these are related by animation.
Maybe the real question here is: how would you (or could you even?) build a "container" view controller like the split view or navigation controller, yourself? Are you required to build the whole damn thing from scratch? I sense that you are, because seems to be hidden wiring in the interaction between view controllers. If so, thoughts on this?
I think the only hidden wiring in view controllers is setting parentViewController, which is required to support the categories declared for split and navigation.
View controllers are designed to be nested, with each controller owning a part of the view hierarchy. The only design goal is that no view controller reach into the view hierarchy of another controller. A parent view controller will usually have some call for adding child controllers so that it can set the frame of the view within the view hierarchy it owns. A child view controller should not do anything to the superview of the view it controls, as that is owned by another controller. Not should it set the center or frame of the view it controls.
For example, a navigation controller has a push method, in which it removes the previous controller view, adds the new controller view, and sets the frame of the newly added view. In general, a parent view controller is free to set the frame of the view of a child controller, but not the bounds.
If you want to change the animation of a navigation controller, I think you would start by implementing every method with an animated: argument. Set up your animation then call super with the animated flag off before committing the animation.
I haven't tried the multiple-view-controllers thing outside of the UIKit-provided ones (navigation/tab-bar/modal/etc) but I don't see why it shouldn't work. Under the hood, everything is a view, though I'll note that UIKit has special views for view controllers which no doubt have some kind of special handling by the system (UIViewController has a wrapper view, UINavigationController has a UINavigationTransitionView or something, ...).
I'd advise not worrying too much about "best practice" — just code something which does what you want. A couple of options:
Stick logic into view classes (ewwww!). One of our apps does this so it can handle rotation in a custom way (views slide in/out instead of rotating). We should've probably implemented our own view controller logic instead.
Break the model into components which correspond to views. Make each view know how to load its component and recursively load subcomponents. Then the view controller only needs to worry about "big picture" stuff.
Also note that you can load multiple nibs into the same view controller by e.g. connecting it to an outlet called editView.The big difference is that it's not done automatically by -[UIViewController loadView] so you need to do something like
-(EditView*)editView {
if (!editView) {
// Loads EditView into the outlet editView
[NSBundle loadNibNamed:#"EditView" owner:self];
}
return editView;
}
You'll also need to worry about adding it to your view hierarchy, unloading it on -(void)viewDidUnload (iPhone OS 3.0+), setting it up in -(void)viewDidLoad in case there was a memory warning during editing mode, etc...
It's not easy, but UI never is.
You need a master-detail view implemented with a split-view/popover-view and controlled with a UISplitViewController.
The master view is the document list and the detail view is the edit view. Each has its own controller. The two controllers themselves are managed by the UISplitViewController.
If you don't use the splitview controller you will just end up hand coding something that works very much like it. This is really the only way to do what you want easily in the API and it is the layout that iPad users will expect.
See Creating a Split View Interface in the iPad programming guide for details.