简体   繁体   中英

Why this kind of release doesn't work?

I have a newbie question about the following:

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    NSArray *anArray;
    anArray = [dictionary objectForKey: [NSString stringWithFormat:@"%d", section]];
    //here dictionary is of type NSDictionary, initialized in another place.
    AnObject *obj = [[AnObject alloc] init];
    obj = [anArray objectAtIndex:0];
    [anArray release];
    return obj.title;
}

If I run it as it is I will get an error. If I don't put [anArray release] it works just fine. I don't quite understand why is this happening?

Thanks.

You absolutely must read and understand the Cocoa Memory Management Rules , in particular the fundamental rule which states:

You take ownership of an object if you create it using a method whose name begins with “alloc” or “new” or contains “copy” (for example, alloc, newObject, or mutableCopy), or if you send it a retain message. You are responsible for relinquishing ownership of objects you own using release or autorelease. Any other time you receive an object, you must not release it.

Now, look at how you got hold of anArray. You used the method objectForKey: It does not start with alloc, nor new, nor does it contain copy. Nor have you retained anArray. Therefore, you do not own anArray. You must not release it.

The above quoted rule is the most important thing to know about programming with Cocoa on the iPhone or Mac without garbage collection. One of the other posters here came up with the acronym NARC (New Alloc Retain Copy) as an aide memoire which is quite handy.

Let's apply the rule to the variable called obj in your code. You obtained that with a call to alloc, therefore you are responsible for releasing it. However, you then obtained it again (overwriting the previous value) with a call to objectForIndex: so after this you must not release it. However, the first value did need releasing and has now leaked. in fact, the alloc line is unnecessary.

You don't need to release anArray because you are not creating it. The dictionary is just giving you a pointer to the one it has.

You do, it appears, have a memory leak where you create the AnObject. On the next line you reassign the variable "obj" to be something you get from anArray. But you have not released the AnObject you created on the line above.

I think your code should look like this:

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    NSArray *anArray;
    anArray = [dictionary objectForKey: [NSString stringWithFormat:@"%d", section]];
    //here dictionary is of type NSDictionary, initialized in another place.
    obj = [anArray objectAtIndex:0];
    return obj.title;
}

You don't need to release what you have not created.

anArray is not allocated, retained, copied or new'd by you, so you don't need to release it.

Also, you have a leak where you create a brand new AnObject instance using alloc/init, but then assign a new value to it straight after, from the array.

Your code should look like:

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    NSArray *anArray;
    anArray = [dictionary objectForKey: [NSString stringWithFormat:@"%d", section]];
    //here dictionary is of type NSDictionary, initialized in another place.
    AnObject *obj = [anArray objectAtIndex:0];
    return obj.title;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM