Why isn't this code leaking?
I am new to development and can not figure this out:
for(NSString *collectionName in jsonObjects)
{
NSDictionary *collection = [[NSDictionary alloc] init];
collection = [jsonObjects valueForKey:collectionName开发者_Go百科];
NSArray *items = [[NSArray alloc] initWithArray:[collection valueForKey:@"items"]];
NSNumber *lastAccess = [[NSNumber alloc] init];
lastAccess = [collection valueForKey:@"lastAccess"];
[items release];
}
I don't understand why it is, that when I DO release either lastAccess or collection, the program crashes with EXC_BAD_ACCESS error..., but if I DONT release items I get a leak. Can anyone please shed light on this. I thought that if you used alloc, then you owned the reference and must therefore release?
There are a bunch of problems with that code. Ignoring, for the moment, that the Foundation caches certain commonly used values.
This pattern makes no sense:
NSDictionary *collection = [[NSDictionary alloc] init];
collection = [jsonObjects valueForKey:collectionName];
The first line creates an (empty) instance of NSDictionary and the second line promptly overwrites the reference to it. Both a leak and entirely pointless; there is no need for the assignment/allocation on the first line. Same goes for lastAccess
later.
Since the second line is returning an un-owned reference, attempting to release
it will cause a crash.
Note that if there is a crash, there will be a backtrace. This question is straightforward enough that it isn't needed, but always look to the backtrace for clues.
Note that you won't actually see a leak of either the NSNumber
or NSDictionary
instances because the Foundation happens to have singletons of those. In the NSNumber case it just doesn't make sense. Empty dictionaries, though, are used pretty often and having a singleton saves memory.
for(NSString *collectionName in jsonObjects)
{
NSDictionary *collection = [[NSDictionary alloc] init]; // Allocation
collection = [jsonObjects valueForKey:collectionName]; // overwriting above, LEAKS
NSArray *items = [[NSArray alloc] initWithArray:[collection valueForKey:@"items"]]; // Allocation
NSNumber *lastAccess = [[NSNumber alloc] init]; // Allocation
lastAccess = [collection valueForKey:@"lastAccess"]; // overwriting above, LEAKs
[items release];
}
calls that don't contain 'alloc' or 'new' return references to object that are 'autoreleased' which means they are not owned by you, releasing them will cause a crash. You can use them but only in the scope of the function that you are in, if you need them for later use you will need to call retain
on them. So when calling accessor functions you only need to declare the variables that you need and not create new objects.
alloc
creates a new object, in the case of collection
you are creating an empty NSDictionary
, but you promptly overwrite the reference to that new object with the autoreleased reference you get from valueForKey:
this will create a leak. As the originally created object won't get released.
probably should look like this
for(NSString *collectionName in jsonObjects)
{
NSDictionary *collection = [jsonObjects valueForKey:collectionName];
NSArray *items = [collection valueForKey:@"items"];
NSNumber *lastAccess = [collection valueForKey:@"lastAccess"];
}
I realize that with the capability of having questions like this answered by a willing crowd reading the manuals has become just a chore but if you want to progress you should have a look, most of the apple documentation is exceptionally well written as these things go. The memory management guide will resolve a lot of questions.
In that code, you're just reassigning the lastAccess
pointer, which leaves the alloc
ed NSNumber
leaked. You need to actually set the value for the NSNumber
object pointed to by lastAccess
.
EDIT:
I had placed some example code, but I'm taking it out, since I realize now that the code sample above has too many issues. Take a look at the documentation for NSDictionary
. With collection
, you're creating an object, and then leaking it by reassigning its pointer to something else. Once you get those issues ironed out, I recommend updating the question with the new code.
Following @bbum above, i'd write your code like this:
for(NSString *collectionName in jsonObjects)
{
NSDictionary *collection = [jsonObjects valueForKey:collectionName];
NSArray *items = [NSArray arrayWithObject:[collection valueForKey:@"items"]];
NSNumber * lastAccess = [collection valueForKey:@"lastAccess"];
}
All variables in this case will be autoreleased, so you don't need to do release them manually.
精彩评论