gamblor87
gamblor87

Reputation: 523

Setting dictionary in singleton causing EXC_BAD_ACCESS

I'm having issues with a singleton I've created. It contains two NSMutableDictionary's, which are read and used in three views (and some modal views) throughout the app.

I've added an MKMapView t plot some of the venues inside the dictionaries on a map. When I use the exact same method/function used in every other view to access the data, I receive an EXC_BAD_ACCESS error pertaining to a deallocated dictionary. This comes from NSZombieEnabled:

CFDictionary retain: message sent to deallocated instance

In a dsym'ed trace, it is the replacement of one dictionary with another that is causing grief. The code I'm using to call the function comes from a MKAnnotationView click:

UIControl *tempButton = sender;
NSString *selectedEventsString = [self.eventsArray objectAtIndex:tempButton.tag];
NSLog(@"eventString: %@", selectedEventsString);
[[EventsManager eventsManager] changeSelectedEventsDictionaryTo:selectedEventsString];

[tempButton release];
[selectedEventsString release];

"selectedEventsString" is coming out to a perfectly corresponding event.

The corresponding code in EventsManager:

-(void)changeSelectedEventsDictionaryTo:(NSString *)eventName {
       NSLog(@"singleton: %@", eventName);
       self.eventString = eventName;
       self.selectedEventsDictionary = [self.eventsDictionary objectForKey:eventName];
}

Both selectedEventsDictionary and eventsDictionary are set as @property (nonatomic, retain) in the .H file, and this is the init function:

+ (EventsManager*)eventsManager {
    if (eventsManager == nil) {
        eventsManager = [[super allocWithZone:NULL] init];
        eventsManager.eventsDictionary = [[NSMutableDictionary alloc] init];
        eventsManager.selectedEventsDictionary = [[NSMutableDictionary alloc] init];
        eventsManager.eventString = [[NSString alloc] init];
        eventsManager.mode = [[NSString alloc] init];
    }

    return eventsManager;
}

This is an example of code used in other views that works fine:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 
    NSUInteger row = [indexPath row];
    NSString *eventString = [self.eventsArray objectAtIndex:row];
    [[EventsManager eventsManager] changeSelectedEventsDictionaryTo:eventString];

    //Modal display code here
}

Any help would be greatly appreciated! I think I've provided all relevant code but let me know if more is needed.

Cheers!

Upvotes: 0

Views: 656

Answers (1)

Joe
Joe

Reputation: 57179

Where to start! I will point out some things that I do see wrong.

First Example. Do not release tempButton and selectedEventString as you never explicitly called retain/copy or alloc and init on them.

UIControl *tempButton = sender;
NSString *selectedEventsString = [self.eventsArray objectAtIndex:tempButton.tag];
NSLog(@"eventString: %@", selectedEventsString);
[[EventsManager eventsManager] changeSelectedEventsDictionaryTo:selectedEventsString];

//DO NOT RELEASE THESE YOU NEVER RETAINED THEM!
[tempButton release];
[selectedEventsString release];

Your static eventsManager is not thread safe which may not be a issue for you but should definitely be looked into.

Read the comments for the following code example

+ (EventsManager*)eventsManager {
    if (eventsManager == nil) { //<-- Not thread safe
        //DO NOT CALL SUPER USE self
        //eventsManager = [[self alloc] init];
        eventsManager = [[super allocWithZone:NULL] init];

        //You need to autorelease these values or use an autoreleased static method
        //eventsManager.eventsDictionary = [NSMutableDictionary dictionary];
        //eventsManager.selectedEventsDictionary = [NSMutableDictionary dictionary];
        eventsManager.eventsDictionary = [[NSMutableDictionary alloc] init];
        eventsManager.selectedEventsDictionary = [[NSMutableDictionary alloc] init];

        //Do not bother setting these at all or just set them to nil
        eventsManager.eventString = [[NSString alloc] init];
        eventsManager.mode = [[NSString alloc] init];
    }

    return eventsManager;
}

Make sure all of those properties are set to retain or copy and that may fix your problem. If you still have an issue after these fixes you can update your question and I will update my answer.

Upvotes: 1

Related Questions