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.
Related
I'm in the process of learning Swift. I wouldn't say I'm a novice, but I'm sure like many learning online I have missed a lot of fundamental steps to understanding what's really going on.
After getting pretty far with my app I am now seeing that my memory management is very poor. I am using SDWebImage caching which is definitely impacted by GIFS, but more to the point I am now learning about retain cycles and deinit.
Could someone please explain why a ViewController inside a UITabBarController deinit is never called?, why this isn't a bad thing? (unless it is) and just general advice/direction on memory management when using a tab bar controller. I have looked into retain cycles and why they are caused and fixed, but that doesn't seem to be my issue according to xCodes instrument tools.
Any advice would be much appreciated
Thanks.
A tab bar controller does not create and destroy the view controllers (tabs) it manages. It holds onto all of them so the user can switch between them as needed. Thus the view controllers from the tabs persist as long as the tab bar controller persists.
If your app's root view controller is a tab bar controller that never goes away, neither will the view controllers for the tabs.
If, instead, you create a tab bar controller and push it onto a nav stack, or present it modally, the tab bar controller will be released when it's popped/dismissed, and the view controllers will then be released as well.
Also, another reason an object may not be deinitialized is because of references. Since you are just starting Swift, I strongly suggest that you look up tutorials on Reference cycles, ARC (automatic reference counting) and memory leaks. They’ll teach you about
weak var
And the proper time to use it. When starting, I’d say it’s not too important, but they are valuable later on when trying to get a job in software development.
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.
I have some general question about navigation controller. I have pushed a table view with navigation controller. (now table view showing) If I click on back button of navigation controller it brings me back to main view, now the memory allocated for table view will get released automatically. Do we need to do extra?
thanks in advance.
In general, as long as you don't maintain a reference to the object, you can safely assume Cocoa Touch will do the right thing. When things aren't drawn on the screen, the APIs generally don't just hold on to them for no reason, so if you're not holding on to them either you're fine.
"Holding on" in this context either means "keeping a reference to" if you're using ARC or "not releaseing" if you aren't.
Before ARC: When you add a UIViewController to the navigation controller's stack you need to release the view controller after pushing the it onto the stack.
No need to do this if your project is ARC enabled. Read up more on ARC.
I'm getting strange navigation bar behaviour, for example when I hit back button the screen displayed is the previous screen, however the Navigation Bar items do change. So I'm left with screen A, but with nav bar buttons for screen B.
Could this be due to memory leaks? I do note with my app still:
This behavior seems to happen:
immediately if I trigger memory
warning via the simulator menu, or
on a device after it has been on
for a while [without being killed
and then restarted as an app].
I do have some memory leaks I'm
trying to clean up (i.e. Profiler
highlights items in "leaked blocks"
section)
Any tips on fault finding root cause of why pushing a back button would end up in a weird state? e.g. screen on previous parent view, but nav bar items don't change...
UPDATE - I have finally removed the memory leaks in my app, however I note the nav bar issue still remains. I guess this doesn't confirm the answer to my question is NO in general, but in my specific case it wasn't the memork leak...
From Apple:
The navigation controller updates the
navigation bar each time the top view
controller changes. Thus, these
changes occur each time a view
controller is pushed onto the stack or
popped from it. When you animate a
push or pop operation, the navigation
controller similarly animates the
change in navigation bar content.
Based on this, I would start by looking for a bug or misconfiguration in your view definitions. Check for any InterfaceBuilder warnings if you defined your views via NIBs. Make sure your view hierarchies are correct in both UIViewControllers. Also check for possible bugs in your view life-cycle methods: viewWillAppear:, viewWillDisappear:, etc,.
Actually, it would be nice if you could post some screenshots and/or code. Thanks!
Any view that is not currently visible and only retained by it's view controller (as a part of the view property of that view controller) will be released (along with any non retained subviews) when a memory warning occurs.
Chances are you are creating the view as a part of init, and not retaining it in the controller (simply letting the view socket hold it from releasing). One way around this is to create properties for the views you create (nonatomic, retain), and after creating them and autoreleasing, assign to those properties, don't forget to assign those properties to nil as a part of dealloc to avoid leaking. Another way is to create your custom view elements in viewDidLoad as opposed to init.
Hard to say without code example from the offending views :)
I've seen something like this happen after calling -[UINavigationController setViewControllers:]. You might try not doing any programatic manipulation of the navigation controller's view controller beyond calling -[UINavigationController pushViewController:animated:].
Greetings. I've got a nav-bar application that's misbehaving. I've got two buttons, one that shows all results from my database and another that shows a subset of my database. Of course, each button has its own action method. Both of these methods instantiate a view controller object of the same class.
If I start the app and only click the "all results" button, I do see all results. The goofy thing is that when I click the button for the subset of results (and see the subset of results), click Back on the nav bar, and then click the first button for the entire set, I see the subset again.
While debugging with break points all over the place, I noticed that the dealloc method of my results view controller doesn't get called. However, when I click Back and then click the all-results button, the alloc/init methods are indeed called again for my results view controller.
So even if I have a blatant memory leak, how is it possible that my freshly allocated/initialized view controller object has the same data as that of the previously instantiated view? Stepping through the code made this problem seem even more bizarre, as it appeared to be behaving properly...just yielding old data.
Any advice at all would be great. Thanks!
Calling "reloadTableData" on the table view should ensure the data is refreshed. Call that in the action methods.
Why do your buttons repeatedly instantiate the view controller? Why not have pointers to the view controllers as instance variables that you only have to set once and then can use at will?
This is just a wild guess, but it could be related to the reuse of tableViewCells. Try always creating a UITableViewCell, avoiding the reuse-identifier to see if the old data persists.
I figured out what was wrong a while ago and thought I would answer my own stupid question. :)
I had forgotten that I made my Database class a singleton and put a master pointer to "allResults" in the app delegate class.
Thanks anyway for your input. Every little bit helps me understand this new environment better.