Do i need to release NSMutableDictionary in this case? - cocoa-touch

Do I need to release dictCellCollectionIndividual in this case?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
... ...
... ...
... ...
// Local declaration of dictCellCollectionIndividual
NSMutableDictionary *dictCellCollectionIndividual;
// Copy the specific dictionary from dictCellCollection to dictCellCollectionIndividual. dict CellCollection is declared elsewhere.
dictCellCollectionIndividual = [dictCellCollection objectForKey:[NSString stringWithFormat:#"%#", [arrayCellCollectionOrder objectAtIndex:indexPath.row]]];
... ...
... ...
... ...
// Do I need to release?
[dictCellCollectionIndividual release];
return cell;
}
Doesn't using objectForKey increase the retain count? Don't I have to release it?
Thanks in advance.

No, it simply returns a pointer to the object held within the dictionary; if you plan to keep the object around for any period of time, you need to take ownership of it, so that the object will remain valid if NSDictionary is deallocated in the meantime. In this case, you'll need to make sure to either release or autorelease the object when you're done with it. If you're planning to use it only as a temporary value (say, as an argument to an NSLog call), it's probably unnecessary to retain the object, and therefore unnecessary to release it.

Related

Application crashing on numberOfRowsSection

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [array count]; // <--- Crashes here
}
I'm not sure why it is crashing considering the array is a simple NSArray.
Your "array" must not be an NSArray. Can you provide some context for where array is defined? Are you using ARC?
A simple test would be to put the following line before that return statement:
NSLog(#"array = %#; array class = %#", array, array.class)
Paste the output from that and I can help you further! My guess currently is that array is being deallocated, and there's some other (or garbage) property in that memory. I wouldn't be surprised if you saw that array.class was an NSNumber...

Can't add to an NSMutableArray with addObject method

I am having an issue with the addObject method of an NSMutableArrayObject. Here's the code I'm using right now:
- (void)addBirdSightingWithName:(NSString *)name location:(NSString *)location {
BirdSighting *bird;
NSDate *today = [NSDate date];
bird = [[BirdSighting alloc] initWithName:name location:location date:today];
[self.masterBirdSightingList addObject:bird];
NSLog(#"Elements: %d", [self.masterBirdSightingList count]);
}
When this code runs, the NSLog call prints the value 0 to the console. I don't know what could be causing this.
EDIT:
I have looked deeper into the code, and I have discovered that the problem is that my BirdSightingDataController is never initialized. Now my question is: Where can I place the init for my BirdSightingDataController? In the viewDidLoad?
Thanks to everyone for the help.
Did you allocate memory to masterBirdSightingList?
self.masterBirdSightingList = [[NSMutableArray alloc] init];
In almost every case where cellForRowAtIndexPath: is not called is because numberOfRowsInSection: returns 0.
Place a log there and make sure you return more than one item and you should be able to see your cells. If you need further help please post the code in your:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
Check your property accessor. Are you sure it's returning the correct object? Make sure the name of the property matches the instance variable or you've specified it correctly (For example: #synthesize masterBirdSightingList = _masterBirdSightingList;. If the property accessor doesn't match the iVar, it will return nil. Of course, if you're manually implementing the accessor check your code there. If you're not, you could also try manually implementing it to make sure.
To do a quick check, remove the self.masterBirdSightingList and replace it with masterBirdSightingList (assuming that's the iVar name) to access the iVar directly and see what happens.

EXC_BAD_ACCESS error when removing object from NSMutableDictionary

I have a NSMutableDictionary as the datasource for my UITableView. I am trying to implement the delete mode and having an issue.
I am logging the key I am trying to remove as well as the object that it corresponds to as this issue seems like it might be related to my trying to access unallocated memory or something. Here is my implementation of tableView:commitEditionStyle:forRowAtIndexPath:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source.
NSArray * keys = [userList allKeys];
NSNumber *keyToRemove = [keys objectAtIndex:indexPath.row];
NSLog(#"Key to remove: %#",keyToRemove);
NSLog(#"Object at key: %#",[userList objectForKey:keyToRemove]);
[userList removeObjectForKey:keyToRemove];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[keys release];
[keyToRemove release];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
}
}
This method runs and then I get the error. The two NSLog statements output the correct key and it's corresponding value.
Can someone tell me what I'm doing wrong?
Thanks
You don't own keys or keysToRemove, so you should not be releasing them. I strongly suggest reading up on the Cocoa memory management rules.
Here's your problem:
[keys release];
[keyToRemove release];
You are releasing keys and keyToRemove, even though you never allocated it, retained it, or copied it, so it's reference count is decreasing more than it should.
As a general rule, you should only release an object if you called alloc, retain (not init, sorry) or copy on it, I recommend you read on reference counting here: Practical Memory Management

UITableView titleForHeaderInSection prints headers to console twice then crashes

In the method below titleForHeaderInSection, for some reason the NSLog prints out the headers twice and then the app crashes in objc_msgSend. I can't understand why this would cause the app to crash?
It would seem from research that crashes in objc_msgSend are caused by sending messages to already freed objects, but is that the case here?
My sectionNames array is populated in viewDidLoad.
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
NSString *title = nil;
title=[sectionNames objectAtIndex:section];
NSLog(title);
return title;
}
Thanks
How are you populating your sectionNames array? It's possible that the array, not the string, is getting released prematurely.
UPDATE:
Your problem is that +arrayWithArray: creates an autoreleased array, which gets released when the current run loop finishes. You need to either retain sectionNames or use -initWithArray:

Balance retain with release?

I am just curious, do I need to add a further [name release] elsewhere to match up with the retain here in the getter?
- (NSString *)name {
return [[name retain] autorelease];
}
gary
No, but you shouldn't need to do this at all since you are not allocating anything. You could simply return name and that should be fine. Was there a reason you needed to add this retain/autorelease?
A little more explanation, what is happening here is that your retain count goes up by one when you do a retain, and then down by 1 when the scope exists because of the autorelease.
I don't know how your variable definition is in your class but the rule is that in your getter you should return the object unchanged for the reference count. It's the responsability of the caller to call retain if it want to keep a reference on it.
- (NSString*) name {
return name;
}
// caller
NSString* name = object.name;
[name retain]; // if necessary. If the string is used only in the context of a method you do not have to retain it.
If you are using the returned value as a field in another class you should define your field like this:
#property(retain, nonatomic) NSString* name;
With this a retain will be called when you assign to the variable.
No, this is fine. autorelease will cause the value to be released when the current autorelease pool is drained.
Every retain must be matched with exactly 1 of either release or autorelease.
However, I believe both the retain and autorelease are unneeded here. Generally you want to use that autorelease idiom because you've alloc'ed something in the method.
No. The autorelease will balance it out. I don't think, however, that the retain and autorelease would be necessary. You can simply use return name.
As others have said, you do not need to retain or autorelease the property. Since callers of the 'getter' method did not create the object, they do not own it, and you are safe to assume that they won't tinker around with its retain count.
But, callers could potentially change the value of the variable returned by the getter, which would affect the object. Therefore, it would probably be a better idea to return a copy of your variable, especially since it is an NSString. (Getters for NSString objects often return a copy.)
- (NSString *)name {
return [[name copy] autorelease];
}
In this scenario, you are creating a copy of the variable, so you 'own' it. By autoreleasing it before it is returned, you ensure that it will survive long enough to be used in the caller's scope, and that any changes they make to the 'name' variable will not affect the underlying object.
I am just curious, do I need to add a further [name release] elsewhere to match up with the retain here in the getter?
- (NSString *)name {
return [[name retain] autorelease];
}
No, because you are already releasing it. autorelease just means “send yourself release later”.
I think you should review the memory-management rules.
I think I might have figured it out:
if [myString] is created outside the method then your safe to use ...
return myString;
if on the other hand [myString] is created inside the method and therefore needs to be released and returned, then you use.
myString = [[NSString alloc] initWithFormat: #"Send me home"];
return [myString autorelease];
This way the method sets [myString] to autorelease, Basically the object is created, set to autorelease and returned. The object will ultimately be released when the pool is destroyed.