How I must remove objects?
For example, I have NSDictionary and some NSStrings from it:
NSDictionary *dict = [NSDictionary dictionaryWithObjects....];
NSString *str = [dict objectForKey:#"key"];
[str release]; or [str dealloc]; or str = nil or it's autorelease object?
If I will remove not autorelease dict, will all child removed too?
Memory management in objective c is based on object ownership. If you own the object you must release that object.
Cocoa sets the following policy:
You own any object you create
You create an object using a method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy” (for example, alloc, newObject, or mutableCopy).
You can take ownership of an object using retain.
When you no longer need it, you must relinquish ownership of an object you own
You relinquish ownership of an object by sending it a release message or an autorelease message.
You must not relinquish ownership of an object you do not own
This is just corollary of the previous policy rules, stated explicitly.
In your case
NSDictionary *dict = [NSDictionary dictionaryWithObjects....];
NSString *str = [dict objectForKey:#"key"];
you are not owner of str, so you should not release that object.
to remove specific objects you will have to make a mutable Object.
Most of the objective-c dat types are mutable such as
NSMutableDictionary,NSMutableArray..etc
then just call ..[yourObject removeObjectatIndex:someInteger] or [yourObject RemoveAllObjects] to remove objects.
Releasing or auto releasing an object is totally different thing..it will free up the memory that whole object(Dict..array..etc) is taking..
If the call does not end in retain, copy or mutableCopy, alloc or new you must not use release or autorelease. The object is already autoreleased.
NSString *str = [[NSString alloc] initWithString:#"123"]; <- needs release
NSString *str = [aString copy]; <- release
NSString *str = [aString mutableCopy]; <- release
NSString *str = [aString retain]; <- release
NSString *str = [NSString new]; <- release
everything else <- don't release.
there is exactly one valid use of dealloc. That is in [super dealloc]; in your - (void)dealloc method.
If the dictionary gets deallocated all the objects and keys it contains get released. If they are not retained somewhere else they get deallocated too.
There is plenty of documentation about memory management available. For example Apples Advanced Memory Management Programming Guide
what do you mean "remove"? assume you mean dealloc or free
str is retained by dict and if you didn't call retain on it than you should not call release on it.
and you should never call dealloc to any object
NSDictionary *dict = [NSDictionary dictionaryWithObjects....];
dict is an autoreleased object with means it will be deallocated on next run loop if you did not retain it anywhere
everything in dict is retained by it so they will not be deallocated until dict is deallocated
Related
Apple's NSCopying docs state that copyWithZone: returns an object that's implicitly retained by the sender. So when that object is added to an NSMutableArray it seems like the object should be sent an autorelease message to keep the retain count balanced (since the array will retain the object).
So to deep copy the contents of one array to another I'd expect something like:
NSMutableArray *destination = [NSMutableArray array];
// assume MyObject adopts NSCopying
for (MyObject *obj in myArray)
[destination addObject:[[obj copy] autorelease]];
However I noticed a different approach in this answer. It seems like [ret addObject:[val copy]] is a memory leak. However I'm brand new to NSCopying so I thought I'd ask: When adding a copied object to an array should the object be sent an autorelease message to keep the retain count balanced?
Edit - more info: Clang reports a potential memory leak after removing the autorelease. Perhaps the linked answer assumes copy returns an object that's not implicitly retained by the sender.
Yes it does need to be released but I wouldn't use autorelease in a loop like that, do it manually with each iteration
for (MyObject *obj in myArray)
{
MyObject *copy = [obj copy];
[destination addObject:copy];
[copy release];
}
I have a simple method in my model to create a NSDictionary object containing its properties.
Unfortunately this method is seen by "Analyse" to be leaking memory :
Potential memory leak of an object allocated on line 76 (marked here with a dot) and stored in 'dic'.
-(NSDictionary*) getDictionary {
NSDictionary *dic = [[NSDictionary alloc] init];
[dic setValue:(id)self.internal_code forKey:#"internal_code"];
[dic setValue:(id)self.identifier forKey:#"id"];
[dic setValue:(id)self.owner forKey:#"owner"];
[dic setValue:(id)self.address forKey:#"address"];
[dic setValue:(id)self.displayed_name forKey:#"displayed_name"];
return dic;
}
I am not using ARC.
PS : To people coming in, the original code I posted was correct — it had an autorelease. I edited it after so the memory leak would reappear and to ask precisely why.
When returning an object from a method that doesn't begin with alloc, copy, mutableCopy or new, that object must be returned as autoreleased.
More conceptually, it should not be owned by your code when you return it. You take ownership of an object when you type alloc, copy, mutableCopy or new. You relinquish ownership when you type release or autorelease.
You can either change your return statement to:
return [dic autorelease];
Or better is to keep the alloc/init/autorelease all on one line so the code is easier to review, and the alloc and release cannot become separated by accident while copy and pasting code:
NSDictionary *dic = [[[NSDictionary alloc] init] autorelease];
An even easier way is to use this convenience constructor on NSDictionary:
NSDictionary *dic = [NSDictionary dictionary];
The above lines will fix the memory leak. However, you are also trying to mutate an immutable type (NSDictionary). You should be using a mutable dictionary instead:
NSMutableDictionary *dic = [NSMutableDictionary dictionary];
Finally, you should ideally be setting values with the setObject:forKey: method, although setValue:forKey: will also work.
For more information on memory management, read the Advanced Memory Management Programming Guide.
If you are targetting iOS 4 or later, I would highly recommend using ARC.
Try to autorelease while returning the dic as below
return[dic autorelease];
If an inited object comes to me retained, so I own it, and I store it in an NSArray, which retains that which gets stored in it, can I count on NSArray to see that it's already retained and not increase the count, or do I need to run through the array and decrement the retain count to insure no memory leak?
Sounds like you need to read the Memory Management Programming Guide. Your case is extremely simple. You own the object. You pass it to the array, which now also owns it. You need to release your ownership of it. Otherwise you'll leak it.
To make sure that the ownership of the object which was added into the NSArray is relinquished, send the -release message to the object right after you add it to the NSArray. If you do not do this, then you will indeed have a memory leak.
This is what happens:
NSString *str = [[NSString alloc] initWithFormat:#"%#", #"Blah"]; //retain count is 1, you own this object
[array addObject:str]; //retain count gets bumped to 2
[str release]; //retain count is 1 - relinquishing ownership here.
//There is no leak because when the NSArray is
//deallocated, the object will be sent the release message.
But if you don't send the owned inserted object the -release message, then even when the NSArray is deallocated, the object will only have a retain count of 1 and the memory obtained by the object will never be reclaimed, thereby resulting in a leak.
Whenever you release the NSArray, it'll release everything it retains.
As such, as long as you release the inited object once you've added it to the NSArray (so it's the only thing that retains it) or release it once you've finished with it outside of the array all should be fine.
Incidentally, there's a good blog post called "objective-c memory management for lazy people" that explains such things pretty well and is a handy reference if you're just starting out with such things.
You don't need to do that. NSArray takes ownership of any object that it stores. It will release its objects when it's deallocated. If you retain an object yourself, you take ownership too, and you are responsible for releasing it too.
NSArray will retain your object when you add it, and then release it when you remove it from the array. This is by design. This means that to ensure there's no memory leak, if you already retained the object before adding it to the array, you should release it after removing it from the array:
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:10];
NSObject *object = [[NSObject alloc] init]; // retain count of 1 (because of alloc)
[object retain]; // useless, just for example, retain count of 2 (because of retain)
[array addObject:object]; // array is mutable, retain count of 3 (because of addObject:)
[array removeObject:object]; // retain count of 2
[object release]; // retain count of 1
[object release]; // retain count of 0, the object is dealloc'd afterwards
[array release]; // to be sure that we are not leaking an array, too
I got a doubt that when should the strings are released.I am not made any allocation to the string is there any necessary to release the string?
No if you do not "allocate" the string they are auto released.
for example
NSString *aTestString = [NSString stringWithFormat:#"Hello %#",#"World"];
This string is auto released, so you do not have to call [aTestString release];
If you would do:
NSString *aTestString = [[NSString alloc] initWithFormat:#"Hello %#",#"World"];
Then you would need to release it by [aTestString release]; because you manually allocated.
Therefore it is wise to autorelease it, so you do not have to think of it later on
NSString *aTestString = [[[NSString alloc] initWithFormat:#"Hello %#",#"World"] autorelease];
But that would just be the same as the first piece of code I gave ya.
Back to the point, no you do not have to manually release it as long as you do not allocate it yourself.
Did you create the string via a call to alloc, new, or a method containing copy? Did you explicitly retain the string yourself? If you got the NSString from a CFStringRef, did you create the CFStringRef with a function that included create? If not, you don't have to do anything. If you did, you have to either release or autorelease the string.
Object allocation/deallocation rules
You need to call [Object release] if and only if:
You called [Object alloc]
You called [Object retain]
You called [Object new]
If you did not explicitly allocate or retain the object, then you need to release it. If you got the object via a class method, the method did something like this: return [[[Object alloc] init] autorelease];. This allocates a new object, but is autoreleased when the NSAutoReleasePool next gets a chance.
The function I'm looking at:
-(void)viewDidLoad {
NSBundle *bundle = [NSBundle mainBundle];
NSString *plistPath = [bundle pathForResource:#"statedictionary" ofType:#"plist"];
NSDictionary *dictionary = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
self.statesZips = dictionary;
[dictionary release];
NSArray *components = [self.stateZips allKeys];
NSArray *sorted = [components sortedArrayUsingSelector:#selector(compare:)];
self.States = sorted;
NSString *selectedState = [self.states objectAtIndex:0];
NSArray *array = [stateZips objectForKey: selectedState];
self.zips = array;
}
Why is an NSDictionary allocated, then assigned to a pointer called *dictionary, and then assigned to the instance variable stateZips? Why not allocate it and assign it directly to the instance variable and save memory of creating and releasing another NSDictionary? The same methodology is always followed, including later in this function with the NSArray...
NSDictionary *dictionary = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
self.statesZips = dictionary;
[dictionary release];
Also, this sorting puts the keys from a hash table (dictionary) in alphabetical order. I'm not sure I understand this line:
NSArray *sorted = [components sortedArrayUsingSelector:#selector(compare:)];
No one seems to have addressed the fact that the line
self.statesZips = dictionary;
is not directly an instance variable assignment. stateZips is a property, and so that line of code calls the setStateZips: method. That method retains or copies the dictionary, so unless the viewDidLoad method intends to use it again for some purpose, it's not needed any longer. That makes it OK to release it.
The previous line:
[[NSDictionary alloc] initWithContentsOfFile:plistPath];
allocates an object. That makes it your responsibility to release it once you don't need it any more. After assigning it to the statesZips property, it's no longer needed, so it's released and you shouldn't use dictionary any more. You'll notice that later code only refers to self.stateZips, not dictionary.
In the case of the NSArray later in the method, viewDidLoad does not allocate the object, so that method is not responsible for calling release on it. The rule of thumb is that if you alloc it, you're responsible for making sure it gets released. Otherwise, it's not your problem.
Sorting the array uses the sortedArrayUsingSelector: method. A selector identifies a method in Objective-C. And the #selector is the literal syntax for selectors (kind of like how #"" is the literal syntax for NSString objects). So, what that code says, is "give me an array where the objects in components are sorted, and use the compare: method to compare each object when you do the sort. When it sorts the array, it will call compare: on the objects in the array to determine how to put them in order.
The statesZips property is probably retained, that's the reasoning.
When the NSDictionary is first allocated, its retain count is 1. When it's assigned to statesZips, the retain count becomes 2. When it's released, the retain count drops to 1, which is usually the desired outcome.
Note that the code below would have produced (almost) the same result:
self.statesZips = [NSDictionary dictionaryWithContentsOfFile:plistPath];
because dictionaryWithContentsOfFile returns an autoreleased object.
As a convention, class methods like [NSDictionary dictionary] return autoreleased objects (which automatically get released after some time), while the usual alloc-init method (as in [[NSDictionary alloc] init]) return retained objects.
I suggest you read the Memory Management Programming Guide for Cocoa for further information.
EDIT: I must have missed the last part of your question when I first read it, but Barry has already answered that part.
This code uses reference-counted memory management (not the automatic garbage collection memory management available in Objective-C 2.0 on OS X). When any object (in this case, the NSDictionary and the NSArray) are alloc'd, the caller is responsible for calling -release on that instance. Failing to call release causes a memory leak. The code could have been written as
self.statesZips = [[[NSDictionary alloc] initWithContentsOfFile:plistPath] autorelease];
but at the expense of less explicit memory management (relying on NSAutoreleasePool to release the alloc'd instance at the end of the event loop iteration.
the call
[components sortedArrayUsingSelector:#selector(compare:)];
returns an array of whose elements come from components but according to the return value of calling [elem1 compare:elem2] to compare two array elements.