I have this 2 "Loops" in my App between my ViewController.
First Loop is the Game-loop. At first VC my Level is displayed. The second VC is my Game Screen and if the game is finished, my third VC will appear with bonus point, stars, and so on.
The second "Loop" are just three VC with swiping.
Ok, where is now the problem? i have problems with the deallocations. for example, overtime i swipe, my locations are going up in sínstruments, the curve is getting higher and higher...
also my game loop. i can't deallocate the vc before.
i think i didn't understand correctly how [self dismissViewControllerAnimated:NO completion:nil]; works.
is it right, that this method is always sent to the parent vc, and the parent vc deallocate the vc where i execute this method?
is the parent vc my initial vc?
how can i dismiss and deallocate my view controllers correctly in my "loops"?
now, my allocing curve in instruments is getting higher and higher at each level, and about level 18-21 my app is crashing, i think because of too much allocations.
can anyone tell me hoe i can solve my problems?
To begin with your questions:
Is it right that this method is always sent to the parent vc, and the parent vc deallocate the vc where I execute this method?
From the Documentation about dismissViewControllerAnimated:completion:
The presenting view controller is responsible for dismissing the view
controller it presented. If you call this method on the presented view
controller itself, UIKit asks the presenting view controller to handle
the dismissal.
Is the parent vc my initial vc?
Parenting is a bit complex with your structure. Normally, when a VC (let's call it X) presents another VC (this one is Y), X would be the parent of Y. But you must share additional code such as how you're allocating these VC's, how/when you're presenting them, etc. to know which one is the "most" parent.
When you call [self presentViewController:Y animated:** completion:** on X;
X would be the presentingViewController.
Y would be the presentedViewController.
Hence, X is the responsible one for Y. Parent :) So, your question is a bit invalid for your scheme. However, you can easily say that your initial VC would probably be the parent of all VC's that's presented by him. (For example, if you embed navigation controller for VC's, it would be the root VC and it will be responsible for "winding/unwinding", which makes it "parent".)
Normally, view controllers should not go in a loop between themselves. They can be dependable on each other, but it shouldn't create loops.
Solution proposal:
It seems to me that you're duplicating these 3 kind of VC's every time a level begins. That's the first loop's problem. The second loop is a bit complex, I assume you want to save the state of the VC's while swiping to the other VC's.
1. Manipulating current VCs.
These VCs must have an option to clear his state, everything should be reset like it was loaded for the first time. You will only create these VCs once, and reset them if needed.
2. Create a Singleton Class which will hold these VCs.
(Caution: Since this solution involves holding VCs up in a class, they will always hold up memory. They won't be drawn to window, though.)
When you start the app, a singleton will be created, and you will also create the VCs needed at the same time. This class should have methods like:
addViewControllerToStack:
showViewController:animated:completion:
resetViewController:
And of course properties to hold these VCs.
3. Control through Singleton
When the user presses up a button like "go to X level", you must interact with the Singleton class you've created. If you're going to dismiss a VC, the Singleton should do that. Also for presentation.
Summary:
With this method, you cannot create multiple VCs of the same type. You can always use the one which is created by your Singleton class, and you can always reuse them. But be cautious, since you're not deallocating any VC, you may end up with residues (like forgetting to reset/remove timers, to reset score, etc).
I've used it in one of my project, which required a view controller with OpenGL. I couldn't dismiss it since it's always doing calculations. And it could've been created only once. The bad part is, it was in the middle of the VC segues. So, whenever I needed to present that VC, I call my Singleton class to show it for me. And I create it only once.
Related
I got some serious problems understanding the viewcontroller stack.
When will my app use a stack to save the previous viewcontrollers? Only if I use a navigation viewcontroller or anytime I use normal viewcontrollers and segue modally between them?
So I was just wondering if I use some sort of chained routine for example, like going from vc 1 to vc 2 and from vc 2 back to vc 1. No navigation controller, just modal segues, no unwinding.
Does my app got performance issues because of a stack (which will grow everytime I go around) or doesn't it make any difference?
----updated
So basicly this is my problem. If I went through the routine of the app, the views get stacked everytime I do a transtition.
UINavigationController will retain any controller you push onto it's navigation stack until you pop it back off.
Any UIViewController will retain a controller it presents modally until that child controller is dismissed.
In either case every controller will at a minimum consume some memory until you remove it. Apps which construct ever expanding stacks of controllers are likely to encounter a number of issues including:
you will eventually run out of memory, how fast depends on how much memory each controller uses.
you may see unexpected side effects if many controllers in the background react to the same event.
users may become confused if they change state in an instance of controller 'A', push an instance of controller 'B' on top of it, and then "return" to a second instance of 'A' added to the top of the state. Since they're looking at a new controller and view whatever selection, scroll position, user input, or other state they set on the previous instance may be lost.
developers, including you, may come to dread touching this app.
I suspect that everyone will have a better experience if you view controller management matches whatever visual metaphor you are presenting to the user.
I've been working on this project for quite some time and I'm almost finished fixing up everything except one thing: memory leaks from viewcontrollers.
Here is my situation : I start in the main root view controller and navigate through VC's(root -> Levels -> Level1) like this
Level1* level1 = [self.storyboard instantiateViewControllerWithIdentifier:#"Level1"];
[self presentViewController:level1 animated:YES completion:nil];
This works fine and all but when I use this way to switch between 2 VC's multiple times, I create the new VC every time and the initial one does not get destroyed.
For example, I'm in level1 VC, decide to go to Upgrades VC, therefore using the methods from above. In my hierarchy of VC's, level1 is still alive when I'm in Upgrades scene. When I go back to the level1 scene, a new one is created with the old one still alive!
Now repeat this process several times and I can find myself with quite a few scenes of level1 VC and Upgrades VC stacked up because the initial VC doesn't get destroyed.
I thought of 2 fixes to this problem: Either I somehow destroy old VC's, which I don't know how, or use a navigation controller, which I don't know how either. I'd really prefer to do it the first way, because with a navigation controller, I fear I have to change quite a lot of stuff on how I navigate through controllers.
What I tried:
[self removeFromParentViewController];
Didn't do anything. I also tried to point the old view to nil( and all properties) once the new view was up, but this did nothing either. My VC's are still alive. If I try to point the view to nil before presenting the new VC, then I get this and a black screen :
Warning: Attempt to present on whose view is not in the window hierarchy!
Edit: I forgot to mention, I'm using ARC so I can't just dealloc stuff and all my views and VC's are done through coding, nothing in storyboard except for 2 things: In the storyboard, I put the VC in landscape mode, what class it inherits from and its storyboard ID
Just a question I've been pondering, 'traditionally' with modal viewcontrollers the presenting 'parent' view controller should dismiss the presented child.
Apple have stated that the presented child should not self dismiss, thus I tend to set up a delegate protocol just to dismiss a modal view controller.
This seems somewhat overkill,
I was wondering since objective C passes by reference anyway, and there wouldn't be a performance cost, couldn't I just pass a reference of the presenting parent viewcontroller to the modally presented child viewcontroller during instantiation and then make a method call back to the parent to dismiss the child?
Sorry if this is a stupid question...
The reason why you typically setup the delegate/protocol for something like this is that it makes your code much less coupled. Say you wanted to present your view as a popover or subview later? You may not think this is needed but it may as the project grows.
Since the parent controller handles its own modals, subviews, and popovers it knows what to do when a button to exit is pressed (or some other action). The modal (in this case) does not necessarily (and shouldn't!) know how it is being presented, hence it should tell its delegate that and let that controller handle it (popViewController, dismissViewController, removeSubview, etc...). This is a large part of understanding OOP and will help keep your code cleaner.
And no, this is not a stupid question in my opinion.
I didn't trust segues much at first (because of crashes if they were not set up correctly and because it wasn't clear to me what was going on under the hood) but I find I am using them more. I still don't exactly "get" what is going on though.
I have a segue between ViewController A and ViewController B with no UINavigationController involved. It does a FlipHorizontal transition, which I like.
When A initiates the segue, what happens to the A instance? I put a log statement in A's viewDidUnload method and it doesn't get called. So is A still lurking around? I'd like to be able to segue back to that same instance of A with all it's vars intact but I haven't been able to figure out how to do that.
As a test, I embedded A in a Nav Controller and tried both a segue and a push to B - and wasn't able to get back to my instance of A. What am I screwing up here?
Remember the difference between the view and the controller. The calling controller is still around, and so is it's view. However, any VIEW that is not on screen can be unloaded by the system. That's when viewDidUnload will get called.
Basically, a controller, like every other object, lives until all references to it are gone. In addition, anything the controller owns is still alive as well. However, while it is still alive, it can get two important messages, which tell it "Get rid of anything you don't need or can rebuild."
One of them is viewDidUnload. The other is didReceiveMemoryWarning.
So, yes, if you have a stack 100 view controllers deep within your NavController, then all 100 view controllers are still around... though some of their views may not be.
Im transitioning from one view controller to another UINavigationController by using a modal segue. Its important for me that this view controller (and its child view controllers) stay in memory so specific references are kept up. Although obviously exactly this not happening. When debugging the viewWillAppear function the rootViewController (viewControllers[0]) reference points to different memory addresses between calls (and contains nil values, my actual problem).
Now there two possibilities which could cause this issue:
The UiNavigationController became destroyed
The rootViewController became destroyed
But to make it really confusing, none of them did happen; neither the UINavigationController nor the rootViewController became destroyed (viewDidUnload not called!).
Edit: Further investigation discovered that the UINavigationController is really recreated for every modal segue. I hope that by maintaining a property i can solve the problem.
I finally ended up by creating my own IBAction functions wich present the controller manually. This works just fine and is coded in less than 5 minutes. One just need to init the controller one time on ViewDidLoad from the storyboard.
Create a strong reference in the main view controller and point your new view controllers to that property. This will keep the view around as long as you need, although this is not recommended for n number of views because it defeats the purpose of a nav controller handling its own creation and removing of views.