I am using reloadSections(...) on my UICollectionView in order to update supplementaryViews (section header views). This works, but when I look at the memory graph I see that I now have twice as many cells in memory. Everything seems to be duplicated.
I noticed this because I saw a new cell being initialized, but deinit was never called. So I inspected with the Debug Memory Graph function.
Is this a bug in my code or is this simply some optimisation UIKit has?
I should perhaps add I have each cell type just once or twice, so there are many cell types in my collection view.
Related
How can I track down abandoned memory if in Xcode Instruments don´t show my custom classes?
So I can see the heap is growing after I perform an action with my app (open a view and go back to the previous in my case) and I could fix some memory issues before by tracking down my mistakes in my code.
Now however, I only see things like in Generation N (= Heapshot N), non-object and I don´t know any more how I can fix the leaks. The responsible caller (not seen in the screenshots) also show no own classes/objects.
Edit
The Showing View is a UIWebView. I searched the web and found rumors that UIWebView doesnt properly releasing data. Could that be the issue? I can´t find any solution.
UIWebView is notorious for causing memory issues.
Make sure you set the UIWebView object's delegate property to nil if you assigned an object to it as documented in the class reference. You can do this in dealloc.
Cleanup the web view in viewWillDisappear:animated: by stopping URL loading with a call to stopLoading and/or setting the HTML string to nil by calling loadHTMLString:baseURL: to workaround any memory being held.
Is there a memory issue regarding the number of items in the list I am displaying in my table view? If the user keeps adding items will the application eventually crash or something due to memory issues?
To answer your questions:
There's no black and white answer to this. To try my best to explain, think of UITableView as sort of like a visual data array. In fact, most people (myself included) use a source data object like an NSArray or an NSDictionary to provide the display data for a UITableView. All the memory limitations that would apply to these objects (arrays and dictionaries) apply to your UITableView, assuming your UITableView is set up properly and you're using the recommended techniques for reusing cells. What this boils down to is: Is it possible to have a very large UITableView? - Yes. How long though, this I don't know. I've created UITableViews with complex subclassed cells and 200 rows and they worked fine. It depends on how you set up the table and the data source you're using. Bear in mind again that the limitation is due to the data source. Have an extremely large array and eventually your device will throw a memory warning. As a best practice, use pagination. There are tonnes of tutorials online to enable paging on UITableViews. Lazy load your images (if any) if they are being downloaded.
Yes you can. You can do lots of amazing things if you're creative enough while subclassing UITableViewCells. Otherwise, you can use the standard UITableViewCell as well. There are two labels on there: The textLabel and the detailTextLabel. Use these two to display the data you want.
Your UITableViewDelegate has a didSelectRowAtIndexPath method which you can implement. As long as your view controller housing the UITableView is set to be it's delegate, it will respond to didSelectRowAtIndexPath.
Just empty the array you're using as a data source (bear in mind that your numberOfRowsInSection data source method MUST use the array count) and call reloadData on the UITableView
EDIT: The question got edited, so only point 1 from the above 4 points applies to the question :) The others are nice to know though
Nothing table-specific, but yes, you will run out.
The most important thing is probably to use dequeueReusableCellWithIdentifier: in your tableView:cellForRowAtIndexPath: delegate method. This basically cuts down memory usage to the number of visible cells (plus one being scrolled into view).
I'm working on a kiosk style slideshow app. I have a UIScrollView which shows the slides, and a factory class, which generates the slides. The "slides" themselves are UIViewController subclasses, which are loaded out from XIB files and customized by the factory class. In my main view controller, I set up the scroll view and start a timer. The timer calls a "reload" method every N seconds, which handles the reload and call to the factory class.
The method that the factory class uses looks something like this:
- (SlideViewController *)slideFromManagedObject:(Slide *)managedObject{
NSInteger slideType = [managedObject slideType];
switch(slideType){
case kSlideTypeA:
{
//
// configure arguments here
//
return [[SlideViewController alloc] initWithArgument:argument] autorelease];
break;
}
//
// More types here...
//
default:
break;
}
}
I haven't yet gotten to the point of defining all of my cases, but the ones that are filled out seem to cause jumps in memory usage. If I add return [[[UIViewController alloc] init] autorelease]; right before the switch/case, I get no visible view, as expected, but I also don't see those memory increases. I'm not sure, but I suspect that it's the "C blocks" that I'm wrapping my slide generation code in.
Some things to note:
When the app starts, I see the memory plateau from about 400 kilobytes to around double that. Then, when the slides progress, any of the slides whose generation code is contained in curly braces is called, the memory plateaus upwards again.
This behavior only seems to happen once per launch - when the app loops through all of the slides, the plateaus to_not_ happen again. However if the app is backgrounded and then relaunched, the plateaus do occur again, consuming even more memory.
When I left the app to run overnight, for about 10 hours and forty minutes, the memory usage had slowly climbed from about 1.44 megabytes to somewhere closer to 1.57 megabytes. I suspect that there are/were some other leaks in there that may have been fixed by my tweaking, but the main jump from about 800 kilobytes to somewhere between 1.4 and 1.5 megabytes is still an issue.
Instruments does not report any leaks, but the plateauing concerns me.
What could be causing the increased memory?
EDIT:
So I don't think it's the blocks, since using an if/else seems to do the same thing.
Here's a screenshot of the Allocations instrument running:
Where could possibly be holding on to these views?
One possible explanation for what you are seeing is some caching that UIKit (I assume) is doing of your objects (don't know what they are, but I think of images mostly).
Caching is often used during transitions and for other internalities of UIKit.
UIKit empties its caches usually when a memory warning is received, so you could try and send one to see what happens. In actuality, I suspect that results of sending a memory warning will not be very easy to analyze, since all of your views are also unloaded, hence memory will go down forcibly. But you can try...
As to how sending a memory warning to the device (as opposed to the simulator), here you find an useful S.O. post.
I have a tableview controller where the data for this table comes in from HTTP requests. When new data comes in (which should be reflected as new rows in my table), but when I call
[self.tableView reloadData]
nothing changes in the table. No new rows! I have log statements in my datasource methods confirming that after I call reloadData, the table asks how many rows and sections to draw. My controller for sure returns the new number of rows like it should, but the table doesn't seem to care. I also checked to make sure my cellForRow... method returned a proper instance of the cell that has been configured with the proper data object. I've never had this problem before!
I'm running iOS 4.2 in the simulator with an iPad app built for 4.2.
Perhaps you may have more than one tableview? You could print pointers of the table from the didSelectRowAtIndexPath: and cellForRowAtIndexPath: delegate methods. Including the description of your self.tableView could also shine some light on the issue.
Sounds like the old model/view confusion. reloadData will merely re-display the data that is already in the data source, not load in new data. You can call
[yourFetchedResultsController performFetch:&*error];
everytime new data is available, to force an immediate update. As you saw, the NSFetchedResultsController will update its results, but when and how often is dependant on whether it has a delegate and whether the cache file name is set. I quote from NSFetchedResultsController Class Reference:
In addition,
NSFetchedResultsController provides
the following features:
It optionally monitors changes to
objects in its associated managed
object context, and reports changes in
the results set to its delegate (see
“The Controller’s Delegate”). It
optionally caches the results of its
computation so that if the same data
is subsequently re-displayed, the work
does not have to be repeated (see “The
Cache”).
A controller thus effectively has three modes of operation, determined by whether it has a delegate and whether the cache file name is set.
No tracking: the delegate is set to
nil. The controller simply provides
access to the data as it was when the
fetch was executed.
Memory-only tracking: the delegate is
non-nil and the file cache name is set
to nil. The controller monitors
objects in its result set and updates
section and ordering information in
response to relevant changes.
Full persistent tracking: the delegate
and the file cache name are non-nil.
The controller monitors objects in its
result set and updates section and
ordering information in response to
relevant changes. The controller
maintains a persistent cache of the
results of its computation.
Are your row heights > 0.0? What does tableView.visibleCells return? I'd verify that my cells have hidden != YES and that frame.size > (0x0)
I'm currently hunting down a memory leak in my app for iPhone. I'm using Instruments to track down the code that is causing the leak (becoming more and more a friend of Instruments!). Now Instruments show two lines: one in dark blue (row 146) and one in a lighter blue (150). From some trial and error I get that they are connected somehow, but not good enough at Objective-C and Memory Management yet to really understand how.
Does anyone know why different colors are used and what could be my problem?
I have tried to release numberForArray but the the app crashes when showing the last line in a picker view.
All ideas appreciated!
(Posting this I also realize that line 139 is redundant! Se there, already an improvement ;-)
Ok, lets take a look at the object allocation/ownership behavior of this code...
numberForArray is assigned the result of -NSString stringWithFormat:, which is an auto-released object. That means that you do not want to release it (as you discovered).
That object is then added to the glucoseLoader NSMutableArray, which will retain it. You loop 100 times, creating 100 objects and adding them to glucoseLoader. When glucoseLoader is released, at line 154, it will also release all the objects added to it.
But wait, there's more: firstComponentRange is created from glucoseLoader using -NSArray initWithArray:. When you do that, all the elements of the source array are added to the destination, which will retain them again.
So, when/how do you release firstComponentRange?
Instruments is telling you that firstComponentRange is not being released (a small leak). Since the array retains its contents, you ate thus also leaking 100 NSString instances, allocated at the line indicated with a darker band (a more significant leak).