Swift - Memory increasing when going 'in' and 'back' from UIViewControllers - ios

I am going in and out of UIViewControllers.
Every time I am going in memory increases, but when I am getting out (pressing Back) memory is not decreasing.
I have weak #IBOutlets, vars and lets.
How can I fix it?
p.s. One of the #IBOutlet is container pointing to another UIViewController

Ignore the comments suggesting retain/release breakpoints and peppering your code with log calls; that's an unwieldy tactic that misses entire classes of problems. Abizern's suggestion to use Instruments is a lot more spot-on. Run the Leaks instrument to look for leaked instances. Browse the other memory instruments as well. Instruments is a &#&$&-ing magical debugging tool and so many developers ignore it for reasons I can't fathom. Spend a few minutes with a tutorial and you'll save months of debugging time over your career.

It sounds like you are creating a new UIViewController every time you switch between views. Try to create the segue to be an unwind segue, this will remove the current view from the stack. Otherwise it appears that you are just continually adding to the stack of views. Tell me if this works.

Related

iOS CPU Activity Suddenly Dies

Long story here, so bear with me...
I have a view controller which, when presented more than three times throughout the life of an application session, will hang and lock and freeze my entire application. Even the Springboard locks up until my app's fully backgrounded! In Xcode's inspector, I noticed rather alarmingly that the memory footprint would jump a good 5-8 MB every time I presented that view, and it wouldn't go down again after dismissal. By the time the fourth invocation rolls around, the app's already using 40 MB of memory.
My first thought was, "OMG, itz a memry leek!" The second one told me to hop into Instruments and track it down.
While the Leaks tool did help some, it only told me that the app was leaking like crazy. All it would tell me was that, somewhere in these four second intervals, I had gained between "4 new leaks" and "17 new leaks." They did correspond to my opening that view, though, and once I started commenting random stuff (and following the sometimes helpful guidance of the Allocations tool), I tracked most of them down to three extra lines of code. "Oh well, I don't need those views anyway!" Those three lines no longer exist, and Instruments no longer complains.
My only complaint here is that my UI still behaves the same! On the fourth presentation, the entire app slows down. Upon further inspection of Xcode's instruments, I see that not only is the memory still going up (only to 30 rather than 40 MB this time), but the CPU activity has tanked!
Ok, granted I should have looked there in the first place, but I ain't perfect!
I ran the app again, and found that the overall CPU activity rose consistently the more I presented that view controller. By the third one, it was up to 40-60%. The main thread seemed pretty clear, and most of the activity was spread between eight other background threads (who knows what all those do).
The fourth time I opened that view, I had expected everything to block like crazy. It didn't. The CPU just... stopped. It was running at around 50-ish% when, by the time my finger had left the screen, it was down at 1%. All of the thread graphs shrunk from spiked stalagmites to tiny waves in a puddle. According to the pie chart, the vast majority of the processor was free to do as it liked. It doesn't like me.
I literally have no clue why it does this. I've been stuck in a room for days now trying to figure this out. Any help or advice would be much appreciated.
Does anyone have any idea why this happens, how this happens, or what I can do to make this not happen?? I'm drawing a blank here...
Thank you so much!
It should be noted that I got these by running the app on my iPhone 5s. Yes, I did try on the simulator, but my little MacBook Air took it like a champ, and was no help in figuring this out, except to tell me that the problem happened on iPhones.
I've run into this before, and the following is my general approach that usually allows me to fix these types of memory leaks.
First I would put a print statement into you viewController to see if your VC is being deallocated when it is being popped.
deinit {
print(self.description)
}
The next step, in the case that the ViewController is not being deallocated, I would start by removing core pieces, bottom up, commenting them out chunks one step at a time, yet leaving the back control that hides the view controller visible. Usually you can isolate the memory leak once you see the deInit get called after removing some code, you may have hit the part that made a strong cycle reference.
One more thing, ensure that all your delegates are declared weak, and search through your code for closures, and check that the closures aren't holding hard references within, especially to self.
Also, checkout this article to see the about using unowned or weak, when passing in instances into a closure, could be helpful.
http://krakendev.io/blog/weak-and-unowned-references-in-swift

Instruments viewcontroller segue not released?

I have a question about Storyboard, Segues and memory management. If I read about it on forums people say this is working properly but I was wondering the following, I made a small video to illustrate:
https://www.youtube.com/watch?v=ixs1Fiv5M9s
I grabbed a source from github explaining segues and unwinding them
I tested this in debugging and indeed I see all functions including dealloc is working
I run instruments and check how many times 2de view controller is created (every time #Persistent is increasing)
I check for changes in memory between the 2 states, and a lot is still in memory? But View controller is gone?
I am looking for the wrong data in instruments? I guess looking for memory leaks using modal and dismissing a view controller is not the right way to do this?
Can somebody explain me how to look for memory leaks? I need this for a much bigger app that is using a lot of segues, and sometimes this app crashes because of memory warnings...

iOS Memory usage keep increasing

I'm new to iOS development.
I'm building a simple bus schedule app that makes a HTTP request, parse XML, and display/save data. I have four table view controllers and two view controllers.
When I start the app, Xcode memory report tells me that its memory usage is ~18MB, which is weird since it's just a simple app. I've looked at similar apps on the app store but they were all less than 10MB. Since it's a bus schedule app, I have it make new requests every 30 seconds to update the time. I noticed that each time I change view to look at another schedule, the memory usage increases and it may go up to 50MB or more.
I looked at Xcode's instrument and it looked like there was no leaks. I also looked at allocations and it looked like live bytes kept increasing every time I switched views.
I am kinda stuck from what to do from here. Can anyone guide me please? Thanks in advance.
Use Heapshot to find memory creep. (see: bbum blog)
Basically, their method is to run the Instruments allocate tool, take a heapshot, run an iteration of your code and another heapshot, repeating 3 or 4 times. This will indicate memory that is allocated and not released during the iterations.
In this case, take a heapshot (called something different now) between downloads.
To figure out the results, disclose to see the individual allocations.
If you need to see where retains, releases, and autoreleases occur for an object use Instruments:
Run in Instruments, in Allocations set "Record reference counts" to on (you will have to stop recording to set the option). Allow the problem code to run, stop recording, then search for the object of interest. After that, you'll need to drill down and you will be able to see where all retains, releases and autoreleases occurred.
First, take a look at heap shots as #Zaph suggested. Well worth your while in terms of seeing what's being allocated and not released.
Another technique I use is to use instruments filtering options to filter the display for just the classes in my app. Then, I look for classes which have unusual number's of living instances. For example, most view controllers usually have only one active instance. If there are more, then something is retaining them. Blocks and notification listeners are often the cause.
In your example screen shot, I noticed two things that I would investigate.
Firstly, you have 365 living core animations taking some 30M. Not sure why, but worth thinking about.
Secondly, near the bottom, I noticed 166 table view cell scroll views. Sounds like a lot. I can't see how many living table view controllers you have, but I'm wondering if they are not reallocing. Filtering this list will help establish what's not being dealloc'd.
Finally, leaks can be useful in finding issues, but most of the time what we would regard as a leak looks ok to instruments. So, looking at memory and numbers of allocated instances is a far better guide to finding where things are not being dealloc'd.
Hard to say without any code, but it looks like you have a retain cycle somewhere.
Try to add a dealloc method to the view controllers and make sure that you enter it whenever the view controller disappears.
You say that you make a new request every 30 seconds. If you use a timer with the view controller as a target, the timer has a strong reference to the view controller and vice versa. You have to invalidate the timer when your view controller disappears.

How do I reload a view from the storyboard (or otherwise manage low memory condition)?

In developing my current app, I ran into some issues that I eventually traced back to a low memory warning. Part of the low memory is coming from my (liberal) use of UIWebViews, which are apparently consuming a lot of memory.
I didn't think this would be an issue, since a view that isn't currently visible should just vanish when the low memory warning is thrown, unfortunately it turns out that anything connected to the UITabBarController remains in the heirarchy and doesn't release. By manually releasing (and then recreating in viewWillAppear) the views, I make things work decently. But it doesn't completely solve the memory warning issue.
So what I need to do is manually release the view -- and the large amount of memory that winds up connected to it -- and then restore it. Since I don't want to build it programmatically (that's what IB is for!), I need to somehow reload it from storyboard.
Or, alternatively, I'm being an idiot and there's something really obvious to make my life easy.
After more experimentation, it turns out that on the one hand, my understanding of view life cycles was slightly flawed, and on the other my experiments were tainted by having accidentally let zombie objects on.
Views will, in fact, unload their contents in a low memory condition and reload them later -- that's part of what 'viewDidLoad' and 'viewDidUnload' are designed for! Putting init code in them, as some tutorials I read did, was a major error. That init code should go in the designated initializer -- even if that can be annoying to figure out which initializer is designated.

UIDatePicker Memory Leak with ARC

I'm making an app that has a few view controllers with UIDatePicker controls.
After having lots of memory warnings, I've done a lot of debugging on the cause. Using instruments, I was able to see that whenever a view controller containing a UIDatePicker appeared, memory usage was going up by 2-3mb. Ultimately, this leads to a memory warning. While I can do so much in here, and have seen a dramatic decrease in crashes since re-writing these functions, I'm still not comfortable with this behaviour and want to fix it.
The UIDatePicker's are part of the XIB file. I've tried taking them out of the XIB and programmatically adding them. This doesn't solve the problem. I've also tried using a (thread-safe" singleton. This limits memory usage to only one instance (so memory usage doesn't increase), but I'm trying to avoid singletons wherever possible. Should I just suck it up and use a singleton?
I'm seeing this behaviour on iOS 5 and 4.3, across all devices that run it. I'm using ARC, as the title suggests.
Instruments does not show any memory leaks.
Here is a screenshot from Instruments. Each step up in usage is when a VC containing a date picker appears. The baseline at the start of the graph is 2.3mb of memory usage.
http://i.stack.imgur.com/1S7ns.png
Cheers!
The tool you want to use here is called heapshot. It will help you narrow down the types of objects that are being incorrectly held onto. As #sudo notes, the problem is probably in your delegate rather than the date picker itself. You're probably not "leaking" in the strictest sense of the term. You're probably just holding onto memory that you didn't mean to (which looks a lot like a leak).
You should take a careful look at whether you have any circular strong references. Do you have objects that have a strong reference to their delegate for instance? That will typically lead to a retain loop (which will never be released under ARC). Heapshot can help you find these objects.
I seem to have solved my own question. As this was an inputView, and I also had a UIToolbar with a "Done" button as the inputAccessoryView.
So now I create these programatically in viewWillAppear. In viewWillDisappear, I set the UITextField's inputView and inputAccessoryView to nil, and the date picker and date picker toolbar to nil.
They are no longer in the XIB file.This seems to work really well - memory spikes up by 3mb, then goes back down the second the views disappear. Now the app is running consistently at under 10mb of live memory - it spikes up to 15mb on occasion but very rarely.
Thanks for the help sudo rm -rf and Rob - heapshot analysis helped to try and get to the bottom of it.

Resources