When I use addSubview method and then removeFromSubview to load next ViewController then after load view some times, my app crash. I have many images on views.
I think my memory isn't released, in spite of I use ARC.
What I should use to make it work? I tried addChildViewController, but then my view aren't loading.
As per memory management guidelines, whenever you say addSubview, the reference count increases by 1 and whenever you say removeFromSuperview the reference count decreases by one. So, if you are removing any view, that you have added to any view, the reference count should be adjusted and should not cause memory leak.
What problem I can foresee is that you are having memory leak in the added view (the view, that you are adding multiple times) and this in order overflowing your memory. Try maintaining the reference counts and it will work perfectly. As an alternate solution, you can also track memory leaks by using instrument tools.
Related
I am displaying an array of movable cards (UIViews) in viewController.
This cards have each set a pan Gesture recogniser that allows them to be moved.
When I move a card up self.removeFromSuperview() is called and the view is removed from the viewController's view.
The problem is that since I have displayed many cards one in top of the other, the first one I move around lags a lot and drops some frames.
After some views are removed tho, the user experience improves and It doesn't drop frames anymore.
I was wondering If there was a limit in how many panGestureRecongizers there may be concurrently.
To investigate more what was causing the issue, I tried to use the Time Profiler tool to see what may cause this traffic on the main thread and this is what I found out:
To be honest I'm pretty new to time profiler tool but what I think I see it's causing the problem is indeed the panGesturerecogniser method.
Is this possible or may I search on another path?
I'm creating a project which uses a UICollectionView. As the user selects a cell this slides them to another UICollectionView of similar nature. Ive been noticing that no matter how I go about this I wind up with mountains of memory usage.
I've been experimenting with placing UICollectionView's in full page UICollectionViewCell's so as to take advantage of the reusability of UICollectionViews. The downside of this approach has been memory retention as the CollectionViews are never fully deallocated. Ive also heard that it is not the best practice to put a UICollectionView in a UICollectionView.
I've experimented with UIPageViewController's containing UIViewController's with the UICollectionView inside. This is more efficient as the UIViewController's can be deallocated as the user swipes back however as long as the user continues to select cells and create new view controllers the memory grows unbounded looking like a mountain.
As a bit of a hybrid I attempted as well to put ViewControllers containing UICollectionView's on UICollectionViewCell's. This method seemed to work best but I had to deallocate the view controllers manually as the user swiped.
Are there any strategies or libraries anyone could recommend that would fit this problem. How can I keep the memory down. I understand I'll need some kind of reusable views.
Ive been looking into this Library so far thank you in advance for all of your advise
Parchment Library
I think I understand what you're saying. You have a UICollectionView that can drill down to another UICollectionView, leaving the first one and its backing data retained until you come back and pop it off. Drilling down further and further allocates more and more memory until you back out.
I'd keep things as simple as possible. Solutions like putting a UICollectionView inside UICollectionViewCells can cause your code to get unnecessarily complicated, resulting in new issues and code that's programmer-hostile. If the user experience that works best is a collection view UI that you can drill down into infinitely, then go with that paradigm.
Your issue is not with UICollectionViews, it's in managing your backing data's memory use. That could be done a few ways. It would help to know what kind of data you have that's so large, and what "large" means, but here are a few approaches that come to mind.
One idea would be to unload any large data when you go to the next screen. For example, if your datasource uses an array with a bunch of large images, clear them out when the next view is pushed. Reload the data when your view appears again, or do it lazily when the view's cells need it, whichever works best for you. This would be the easiest approach and probably take care of your memory concerns.
A second approach would be to use one UICollectionView and use custom animations so it looks like a new collection view is pushing/popping from an old one, when in fact you're just changing the data for the collection view and reloading. You could even provide animations that are more interesting than pushing/popping.
On top of either of these approaches, you could implement the UICollectionView prefetch API calls to load data just before you need it. That will reduce your memory footprint even further.
All of these approaches assume that you can load the data to display from storage-- that it's not just in memory from recent webservice requests. Your users are guaranteed a miserable experience if your app has to keep requesting the same large data from the web over and over. So, if you don't have the data stored locally already, set up a cache.
Regardless of the approach, this is something you should be able to handle without adopting a library. UICollectionViews are designed to be memory friendly. Your issue is really in determining the best way to manage your backing data's memory use.
I am using allocations to test my decompression code for my app. I use a Master UITableViewController to display 11 filenames. the test app screenshot is as followings:
when you select one, it will push a UIViewController to display the file, then come back to Master UITableViewController.
Now if you repeat to select one cell, there is no memory spike in the chart. But if you select from 1 to 2, it will increase at least 224KB memory between the generations. I test from 1 to 11. all these changes will will increase almost the same memory. the screenshot is as followings:
I check the detail find there is a VM:UITableViewCellSelectedBackground(CALayer) (some named VM:CoreAnimation, but all are the same 224KB) in the growth. And if i select the selected cells, there is no such big memory spike. it seems they will only be created at the first time one cell is selected.
Now my question is why are they come out? is this a kind of memory leak? and if yes, how can i fix it? Any help would be much appreciated.
UPDATE:
i have confirmed there is nothing related to my decompression code, if i comment out the decompression code, the VM:UITableViewCellSelectedBackground(CALayer) is still there when selected a new cell.
I have tested in simulator, result is similar to you. But memory will fall down after a while.
I don't think this is memory leak. When we select one cell, system may add a translucent layer above the it.
The layer is created when needed so it increase the memory.
I am sure once one cell is selected, the system will create some objects (something is related to the layer or the layer itself) that won't be released though the cell is deselected later, those objects maybe some cache to improve the performance when the cell is selected next time.
In my iPhone application utilizing ARC pushing certain view controllers leads to large memory allocations which are not released. Most of the Live Bytes have the header VM: CoreAnimation
I have tried wrapping various pieces of code, such as pushing the view controller, with #autoreleasepool { } but it doesn't make any difference. Setting the view controllers to nil once they are no longer needed also doesn't help.
Your help and advice will be much appreciated!
UPDATE
I realised that the timing of the memory allocations coincided with a detail view with a CorePlot chart being pushed from a table view. The detail view was also referenced in the table view's header file. One issue was that I was setting the detail view to nil and then reallocating it prior to it being pushed. If I instead initiate the detail view once only when the table view is first loaded, and then refresh its contents before each push, the memory allocation only happens once.
However, I have not been able to completely solve the issue as there is still a large memory allocation when the detail view is first pushed, which is never released.
Perhaps you are using CoreGraphics framework for drawing something on view's, but you are not releasing coreGraphics object. CoreGraphics object is not released by ARC it must be retain/release manually.
I discovered that the memory issues were caused by the creation of new Core-Plot charts that were not releasing their memory when I attempted to deallocate them.
I managed to improve performance using this function when I try to deallocate the charts:
[graph removePlot:plot];
This has been sufficient to significantly improve the situation, although I am still struggling to get 100% memory release. From reading the Core Plot forums it appears I am not the only one to have experienced such issues...
https://groups.google.com/forum/#!searchin/coreplot-discuss/memory/coreplot-discuss/nWui9VjnMtQ/er2FO3o9syYJ
Part of the app I'm working on involves a UIPageViewController, where each page displays an 'entry' that is stored in Core Data. An entry includes, among other things, some images that are being compressed and stored as NSData. Thus, to load these images and display them on a page, I'm using imageWithData, i.e.
photo.image = [UIImage imageWithData:entry.photo];
The problem is that imageWithData is not particularly quick, and so flipping through pages is not as responsive as I would like. My best attempt at remedying this situation has been to preload a number of the view controllers that are displayed by my UIPageViewController into an array. (Not sure if that's the best thing to do, but there you have it)
So, to clarify, I have a navigation controller, which contains viewControllerA, which then links to viewControllerB - which displays the UIPageView and the entryControllers (one entryController on each page). The problem is that when I use the navigation bar to go back from viewControllerB to viewControllerA, I want viewControllerB's array of entryControllers to be released from memory. But, ARC doesn't seem to be doing so. Therefore, after going back and forth between viewControllerA and viewControllerB a few times, turning a few pages each time, I start to get memory warnings - which ends up clearing the current array of entryControllers, and defeats the purpose of having that array, since the entries then have to be reloaded every time I get a memory warning.
In short, ARC isn't clearing any of the memory I've allocated for viewControllerB when I go back to viewControllerA via my navigation controller. I don't like that. If anyone could suggest a reason that this is happening, or let me know if I'm going about this whole thing the wrong way, it would be hugely appreciated. I'm just trying to speed up the transition from one page to the next!
Thanks a bunch.
The only reason for ARC to not release your memory is that you still are retaining it somewhere. Only you know where that is.
Usually, this is caused by a retain cycle, which can happen easily with blocks.
However, it is just as likely that you are keeping a pointer to the object someplace, in a controller, an iVar, or some collection.
Have you run the static analyzer on your code? It's pretty good at finding some of those things.
What does instruments tell you? It's got some neat tools for finding leaks and retain cycles.
EDIT
You can have as many references to any object that you want. Once the count goes to zero, it will be released.
The problem is that you are holding an array of strong pointers to view controllers as a cache. If you want them released, you have to manually nil those pointers. You are somehow pre-loading controllers into an array. They will stay alive until you unload them.
So, as long as you have a strong pointer to something, it will stay around.
Jody's edit, specifically mentioning setting pointers to nil, is what got the ball rolling for me in terms of understanding, and in the end I was able to figure out my problem by setting certain pointers to nil when my "viewControllerB" disappeared. Along the way, however, I also realized another important point - large images in core data are a huge memory burden, and in iOS 5, this can be remedied by setting an option to allow for external storage. So for anyone else who's a relative beginner like me and might come across a similar memory problem, this is a key way to limit the amount of memory being eaten by managed objects storing large amounts of data - your images (or whatever large amount of data) are saved to file automatically, without you having to do anything different in code.