Memory release objective c - ios

Point of my view, when we create object and then set it = nil, this object will be release. but I tried to insert a lot of data to NSMutableDictionary, and then i set NIL for each object. Memory still be there and did not decrease. Please see my code:
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableDictionary*frameAnotationLeft=[[NSMutableDictionary alloc] init];;
// Do any additional setup after loading the view, typically from a nib.
NSMutableDictionary * testDict = [[NSMutableDictionary alloc] init];
frameAnotationLeft = [[NSMutableDictionary alloc] init];
for ( int j=0; j<1000; j++) {
for (int i= 0; i<5000; i++) {
NSString* __weak test = #"dule.For the most part, Automatic Reference Counting lets you completely forget about memory management. The idea is to focus on high-level functionality instead of the underlying memory management. The only thing you need to worry about are retain cycles, which was covered in the Properties module.For the most part, Automatic Reference Counting lets you completely forget about memory management. The idea is to focus on high-level functionality instead of the underlying memory management. The only thing you need to worry about are retain cycles, which was covered in the Properties module.For the most part, Automatic Reference Counting lets you completely forget about memory management. The idea is to focus on high-level functionality instead of the underlying memory management. The only thing you need to worry about are retain cycles, which was covered in the Properties module.For the most part, Automatic Reference Counting lets you completely forget about memory management. The idea is to focus on high-level functionality instead of the underlying memory management. The only thing you need to worry about are retain cycles, which was covered in the Properties module.";
NSMutableArray * arrayTest = [[NSMutableArray alloc] init];
[arrayTest addObject:test];
test = nil;
[testDict setObject:arrayTest forKey:[NSString stringWithFormat:#"%d",i]];
arrayTest = nil;
}
[frameAnotationLeft setObject:testDict forKey:[NSString stringWithFormat:#"%d",j]];
}
testDict = nil;
// Begin to release memory
for (NSString* key in frameAnotationLeft) {
NSMutableDictionary *testDict2 = (NSMutableDictionary*)[frameAnotationLeft objectForKey:key];
for (NSString* key2 in testDict2) {
NSMutableArray * arrayTest = (NSMutableArray *)[testDict2 objectForKey:key2];
NSString* test = [arrayTest objectAtIndex:0];
[arrayTest removeAllObjects];
test = nil;
arrayTest = nil;
}
[testDict2 removeAllObjects];
testDict2 = nil;
}
[frameAnotationLeft removeAllObjects];
frameAnotationLeft = nil;
}
Memory when i run it is 218 mb. and it did not decrease. Someone can help me and give me solution? Thank so muuch

If you are using ARC, setting local variables to nil is unnecessary and will have no effect. Local variables are completely memory-managed for you. And setting a variable to nil does not, as you imagine, cause the memory itself to be cleared; it reduces the object's retain count, but that's all. If the object's retain count has fallen to zero, then the memory may be reclaimed at some future time, but you have no control over when that will happen. Thus, your nil setting does nothing whatever, because the same thing is being done for you by ARC anyway.
If you are concerned about accumulation of secondary autoreleased objects during a tight loop (as here), simply wrap the interior of the loop in an #autoreleasepool block.

Related

NSMutableArray initializing from viewDidLoad

arrayOfElements = [NSMutableArray arrayWithArray:[someObj getArray]];
and
arrayOfElements = [[NSMutableArray alloc] init];
arrayOfElements = [someObj getArray];
What's the difference?
The first arrayOfElements does not seem to lose its objects when it returns count in numberOfRowsInSection:(NSInteger)section, but the second one does. I get EXC_BAD_ACCESS when I do it the second way.
EDIT:
Can I suppose now that this is the best way,
arrayOfElements = [[NSMutableArray alloc] initWithArray:[someObj getArray]];
because I am initializing an array with the contents of whatever will be autorelease'd, and I now have a fully independent array in the current class, that is viewDidLoad, oops sorry, ViewController.
This line creates an NSMutableArray from an existing array
arrayOfElements = [NSMutableArray arrayWithArray:[someObj getArray]];
This combination first creates an NSMutableArray and then instantly discards it replacing it with what is returned by [someObj getArray]
arrayOfElements = [[NSMutableArray alloc] init]; // Create new NSMutableArray
arrayOfElements = [someObj getArray]; // Throw away the newly created array and replace with the result of [someObj getArray]
If you are not using ARC then it is purely by luck that either would work.
In both cases arrayOfElements is being assigned an autorelease'd object - which will be cleared soon (most likely the next runloop). It is only by chance that nothing else has been written over this point of memory which allows one of your implementations to still work.
If you are not using ARC then really you should update your project to be using it will handle a lot of cases like this for you.
You should definitely be using properties (not bare ivars) as this will help reduce memory issues (for non-ARC) and give a more consistent interface to your code.
In your header (or class extension) declare the property like this
#property (nonatomic, strong) NSMutableArray *arrayOfElements;
Now for ARC you can simple do
[self setArrayOfElements:[[someObj getArray] mutableCopy];
for non-ARC you can do
NSMutableArray *array = [[someObj getArray] mutableCopy];
[self setArrayOfElements:array];
[array release]; array = nil;
Also note that getArray is a bad method name.
The use of “get” is unnecessary, unless one or more values are returned indirectly.
Coding Guidelines
When you are adding objects to mutable array from another array, try this:
[arrayOfElements addObjectsFromArray: [someObj getArray]];
If you're not using ARC, you need to make sure its retained.
if (arrayOfElements) {
[arrayOfElements release];
}
arrayOfElements = [[NSMutableArray alloc] initWithArray:[someObj getArray]];

Advice on MKAnnotation and NSString memory leak issues

I'm making an app that displays the user on the map along with multiple restaurant listings. When the user taps a pin, it stores the coordinates from the annotation and compares them against the users to ensure they are different. Once it is determined that they are different, it sends the coordinates of the business along with the coordinates of the user to Google to request directions. The code is working fine, but in order for it to do so I had to declare a few variables in ways that cause memory leaks. I'm hoping to clean the code up and learn where I erred and the proper way this should be handled.
So below is my code for getting the coordinates from the annotation that was tapped. If I attempt to initialize selectedAnnotation and allocate it's memory in say viewDidLoad by putting selectedAnnotation = [[MapLocation alloc] init]; Then it still shows up as a memory leak. And for reference, selectedAnnotation is a MapLocation(that conforms to MKAnnotation) variable, and as a property I have it (nonatomic, retain) and #synthesize(d).
I thought as long as I allocated it in memory, so long as I set its value to nil in viewDidUnload and released it in dealloc, that there should be no memory issues. What am I missing? Below is a screen shot of my memory leaks when I allocate the memory for selectedAnnotation in viewDidLoad along with the code provided below. If I have already allocated the memory, and check that the variable exists, why would it allocate the memory for the variable again? This happens for any restaurant pin I click on, but obviously not on the user's pin, because I have the code to release it in that case.
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
//NSLog(#"Selected annotation view");
// if we don't have the place holder already allocated
// lazy load the MapLocation placeholder variable
if(!selectedAnnotation)
{
selectedAnnotation = [[MapLocation alloc] init];
}
// save the annotation clicked
selectedAnnotation = view.annotation;
// if the annotation selected was is the same as the user's location
if((selectedAnnotation.coordinate.latitude == savedUserLocation.coordinate.latitude) && (selectedAnnotation.coordinate.longitude == savedUserLocation.coordinate.longitude))
{
// set it to nil and release it
selectedAnnotation = nil;
[selectedAnnotation release];
}
}
I'm having similar trouble with memory issues with the method below. I'm bringing in the JSON data from Google, to extract the address and coordinates of the user's location to display in the AnnotationView. I created all the necessary Arrays and Dictionaries to access the information, but once I allocate the memory for them and assign their values to savedUserLocation, if I try releasing say the NSDictionary variable userLocation, even as the last line of code in this method, the app crashes due to "[CFDictionary release]: message sent to deallocated instance 0x83ccb60". I'm pretty sure it's because I'm setting the values in savedUserLocation via pointer, and once the memory is released that information no longer exists, so what would be the proper way to allocate/release the memory to where I can access the information, without causing memory leaks? I've also tried using autorelease, but the same issues persist.
Here is the code that places the user pin.
- (void)fetchedData:(NSData *)responseData
{
//parse out the json data
NSError *error;
NSDictionary *json = [NSJSONSerialization
JSONObjectWithData:responseData //1
options:kNilOptions
error:&error];
NSArray *results = [json objectForKey:#"results"]; //2
NSUInteger counter = [results count];
NSDictionary *userLocation = [[NSDictionary alloc] init];
//NSString *address = [[NSString alloc] init];
for(NSUInteger i=0; i < counter; i++)
{
userLocation = [results objectAtIndex:i];
// 2) Get the funded amount and loan amount
NSString *address = [[NSString alloc] initWithString:[userLocation objectForKey:#"formatted_address"]];
NSArray *types = [userLocation objectForKey:#"types"];
NSDictionary *geometry = [userLocation objectForKey:#"geometry"];
NSDictionary *location = [geometry objectForKey:#"location"];
float lat = [[location objectForKey:#"lat"] floatValue];
float lon = [[location objectForKey:#"lng"] floatValue];
CLLocationCoordinate2D newCoordinates;
newCoordinates.latitude = lat;
newCoordinates.longitude = lon;
// count how many types there are
NSUInteger numberOfTypes = [types count];
NSString *type = [[NSString alloc] init];
for(NSUInteger j=0; j < numberOfTypes; j++)
{
type = [types objectAtIndex:j];
if([type rangeOfString:#"street_address" options:NSCaseInsensitiveSearch].location != NSNotFound)
{
NSLog(#"%#", address);
if(!savedUserLocation)
{
savedUserLocation = [[MapLocation alloc] init];
}
[savedUserLocation setTitle:#"You are here!"];
[savedUserLocation setSubtitle:address];
[savedUserLocation setCoordinate:newCoordinates];
}
}
}
// determine which location is closest to the user by calling this function
MapLocation *closestLocation = [self determineClosestLocationToUser:allLocations locationOfUser:savedUserLocation];
// send in the user location and the closest store to them to determine appropriate zoom level and
// to center the map between the two
[self determineMapCenterAndZoomLevelFromUser:savedUserLocation andClosestLocation:closestLocation];
if(!pinDropped)
{
// add the annotation to the map and then release it
[mapView addAnnotation:savedUserLocation];
pinDropped = true;
}
}
Thanks for any and all help/suggestions/advice. I'd really like to understand the nuts and bolts of what I'm doing wrong, as I thought I had a pretty decent grasp on it.
In didSelectAnnotationView, you have this code:
selectedAnnotation = nil;
[selectedAnnotation release];
This causes a memory leak because you are setting selectedAnnotation to nil and then calling release on it.
The call to release does nothing because selectedAnnotation is nil at that point and a call to nil does nothing. This means the memory that had been allocated is never released but since the pointer variable has been set to nil, when didSelectAnnotationView is called again, your code allocates a new object.
You should switch the order of the two statements (call release first and then set to nil).
However, you don't need to alloc a new object just to keep a reference to the "selected annotation".
Declaring a regular ivar (not a retain property) and just setting it equal to the selected annotation should work.
In addition, the map view already has a property called selectedAnnotations which you should be able to use (so you don't need to maintain your own ivar or property). The map view's property is an NSArray but will always contain either 0 or 1 object(s). Be sure to check its count before accessing the object at index 0.
In fetchedData, you have several memory leaks caused by unnecessary alloc calls.
They are not needed because after calling alloc, you are then directly assigning a new reference to the pointer you just allocated memory for.
For example, userLocation is alloc'd before the for-loop but then inside the loop you directly point that variable to an object in the results array.
This means the memory that had originally been allocated for userLocation becomes abandoned with no reference to it. When you try to call release on userLocation, it is trying to release an object that was not allocated by code in fetchedData.
To fix at least userLocation, just declare the variable and don't alloc/init/release it.
The variables address and type (the NSString) have a similar issue.

Memory leak even though every alloc is released

The last two days I spent with hunting down memory leaks. I´ve read the documentation and searched the internet for good information (e.g. Owen Goss "Finding and Fixing Memory Leaks in iOS Apps"), but still I have too many mysteries to solve.
For example this piece of code lights up in Instruments again and again. I tried my best but can´t fix it.
- (void) updateUserDefaults
{
// alloc temporary Array for object´s positions
NSMutableArray *tArray = [[NSMutableArray alloc] init];
// store locations of objects
for (int i=0; i<[originalOrigins count]; ++i) {
CGPoint foo = [self.view viewWithTag:100+i].center;
NSString *moo = NSStringFromCGPoint(foo);
[tArray addObject:moo];
[moo release]; //?
}
// retrieve all stored positions for all objects
NSMutableArray *zettelPannedOrigins = [[[[NSUserDefaults standardUserDefaults] objectForKey:#"zettelPannedOrigins"] mutableCopy] retain];
// replace with objects from this level
[zettelPannedOrigins replaceObjectAtIndex:zettelAtIndexInTonebank withObject:tArray];
// save
[[NSUserDefaults standardUserDefaults] setObject:zettelPannedOrigins forKey:#"zettelPannedOrigins"];
[[NSUserDefaults standardUserDefaults] synchronize];
// clean up memory
[tArray release];
[zettelPannedOrigins release]; //?
}
What I think might be interesting for others too is, that I release what I alloc. But still it is leaking. This I can´t answer with the documentation. Or can I?
NSMutableArray *zettelPannedOrigins = [[[[NSUserDefaults standardUserDefaults] objectForKey:#"zettelPannedOrigins"] mutableCopy] retain];
This will have a retain count of 2, as mutableCopy retains it once and you are calling retain on it again. Don't call retain here.
Remember, if you call a method with new, alloc, retain or copy in the name, you then own that object and the retain count goes up.
[NSObject mutableCopy]; will give you back an object with increased retainCount by 1 so you do not need another 'retain'.
NSMutableArray *zettelPannedOrigins = [[[[NSUserDefaults standardUserDefaults] objectForKey:#"zettelPannedOrigins"] mutableCopy] autorelease];
This should do the job :)

Where are the memory leaks in my for ... in loop with addObject

There seem to be some memory leaks in the following loop:
NSMutableArray *array1 = [[NSMutableArray alloc] init];
for(SomeClass *someObject in array2){ //has already been populated;
if (someObject.field == desiredValue){
[array1 addObject:someObject];
}
}
//EDIT:
//use array1 for very secret operations
[array1 release];
Any ideas why?
Are you releasing all your retained properties in SomeClass of yours? Make sure in dealloc release all retained properties.. Make sure your SomeClass is leak free..

Objective-C: Fixing memory management in a method

I'm almost there understanding simple reference counting / memory management in Objective-C, however I'm having a difficult time with the following code. I'm releasing mutableDict (commented in the code below) and it's causing detrimental behavior in my code. If I let the memory leak, it works as expected, but that's clearly not the answer here. ;-) Would any of you more experienced folks be kind enough to point me in the right direction as how I can re-write any of this method to better handle my memory footprint? Mainly with how I'm managing NSMutableDictionary *mutableDict, as that is the big culprit here. I'd like to understand the problem, and not just copy/paste code -- so some comments/feedback is ideal. Thanks all.
- (NSArray *)createArrayWithDictionaries:(NSString *)xmlDocument
withXPath:(NSString *)XPathStr {
NSError *theError = nil;
NSMutableArray *mutableArray = [[[NSMutableArray alloc] init] autorelease];
//NSMutableDictionary *mutableDict = [[NSMutableDictionary alloc] init];
CXMLDocument *theXMLDocument = [[[CXMLDocument alloc] initWithXMLString:xmlDocument options:0 error:&theError] retain];
NSArray *nodes = [theXMLDocument nodesForXPath:XPathStr error:&theError];
int i, j, cnt = [nodes count];
for(i=0; i < cnt; i++) {
CXMLElement *xmlElement = [nodes objectAtIndex:i];
if(nil != xmlElement) {
NSArray *attributes = [NSArray array];
attributes = [xmlElement attributes];
int attrCnt = [attributes count];
NSMutableDictionary *mutableDict = [[NSMutableDictionary alloc] init];
for(j = 0; j < attrCnt; j++) {
if([[[attributes objectAtIndex:j] name] isKindOfClass:[NSString class]])
[mutableDict setValue:[[attributes objectAtIndex:j] stringValue] forKey:[[attributes objectAtIndex:j] name]];
else
continue;
}
if(nil != mutableDict) {
[mutableArray addObject:mutableDict];
}
[mutableDict release]; // This is causing bad things to happen.
}
}
return (NSArray *)mutableArray;
}
Here's an equivalent rewrite of your code:
- (NSArray *)attributeDictionaries:(NSString *)xmlDocument withXPath:(NSString *)XPathStr {
NSError *theError = nil;
NSMutableArray *dictionaries = [NSMutableArray array];
CXMLDocument *theXMLDocument = [[CXMLDocument alloc] initWithXMLString:xmlDocument options:0 error:&theError];
NSArray *nodes = [theXMLDocument nodesForXPath:XPathStr error:&theError];
for (CXMLElement *xmlElement in nodes) {
NSArray *attributes = [xmlElement attributes];
NSMutableDictionary *attributeDictionary = [NSMutableDictionary dictionary];
for (CXMLNode *attribute in attributes) {
[attributeDictionary setObject:[attribute stringValue] forKey:[attribute name]];
}
[dictionaries addObject:attributeDictionary];
}
[theXMLDocument release];
return attributeDictionaries;
}
Notice I only did reference counting on theXMLDocument. That's because the arrays and dictionaries live beyond the scope of this method. The array and dictionary class methods create autoreleased instances of NSArray and NSMutableDictionary objects. If the caller doesn't explicitly retain them, they'll be automatically released on the next go-round of the application's event loop.
I also removed code that was never going to be executed. The CXMLNode name method says it returns a string, so that test will always be true.
If mutableDict is nil, you have bigger problems. It's better that it throws an exception than silently fail, so I did away with that test, too.
I also used the relatively new for enumeration syntax, which does away with your counter variables.
I renamed some variables and the method to be a little bit more Cocoa-ish. Cocoa is different from most languages in that it's generally considered incorrect to use a verb like "create" unless you specifically want to make the caller responsible for releasing whatever object you return.
You didn't do anything with theError. You should either check it and report the error, or else pass in nil if you're not going to check it. There's no sense in making the app build an error object you're not going to use.
I hope this helps get you pointed in the right direction.
Well, releasing mutableDict really shouldn't be causing any problems because the line above it (adding mutableDict to mutableArray) will retain it automatically. While I'm not sure what exactly is going wrong with your code (you didn't specify what "bad things" means), there's a few general things I would suggest:
Don't autorelease mutableArray right away. Let it be a regular alloc/init statement and autorelease it when you return it ("return [mutableArray autorelease];").
theXMLDocument is leaking, be sure to release that before returning. Also, you do not need to retain it like you are. alloc/init does the job by starting the object retain count at 1, retaining it again just ensures it leaks forever. Get rid of the retain and release it before returning and it won't leak.
Just a tip: be sure that you retain the return value of this method when using it elsewhere - the result has been autoreleased as isn't guaranteed to be around when you need it unless you explicitly retain/release it somewhere.
Otherwise, this code should work. If it still doesn't, one other thing I would try is maybe doing [mutableArray addObject:[mutableDict copy]] to ensure that mutableDict causes you no problems when it is released.
In Memory Management Programming Guide under the topic Returning Objects from Methods (scroll down a bit), there are a few simple examples on how to return objects from a method with the correct memory managment.

Resources