views:

260

answers:

1

Check it:

- (IBAction)toggleFavorite {
    DataManager *data = [DataManager sharedDataManager];
    NSMutableSet *favorites = data.favorites;

    if (thisEvent.isFavorite == YES) {
        NSLog(@"Toggling off");
        thisEvent.isFavorite = NO;
        [favorites removeObject:thisEvent.guid];
        [favoriteIcon setImage:[UIImage imageNamed:@"notFavorite.png"] forState:UIControlStateNormal];
    }
    else {
        NSLog(@"Toggling on, adding %@", thisEvent.guid);
        thisEvent.isFavorite = YES;
        [favorites addObject:thisEvent.guid];
        [favoriteIcon setImage:[UIImage imageNamed:@"isFavorite.png"] forState:UIControlStateNormal];
    }
    NSLog(@"favorites array now contains %d members", [favorites count]);
}

This is fired from a custom UIButton. The UI part works great--toggles the image used for the button, and I can see from other stuff that the thisEvent.isFavorite BOOL is toggling happily. I can also see in the debugger that I'm getting my DataManager singleton.

But here's my NSLog:

2010-05-13 08:24:32.946 MyApp[924:207] Toggling on, adding 05db685f65e2
2010-05-13 08:24:32.947 MyApp[924:207] favorites array now contains 0 members
2010-05-13 08:24:33.666 MyApp[924:207] Toggling off
2010-05-13 08:24:33.666 MyApp[924:207] favorites array now contains 0 members
2010-05-13 08:24:34.060 MyApp[924:207] Toggling on, adding 05db685f65e2
2010-05-13 08:24:34.061 MyApp[924:207] favorites array now contains 0 members
2010-05-13 08:24:34.296 MyApp[924:207] Toggling off
2010-05-13 08:24:34.297 MyApp[924:207] favorites array now contains 0 members

Worst part is, this USED to work, and I don't know what I did to break it.

--EDIT: By request, my shared data singleton code:

.h

#import <Foundation/Foundation.h>

@interface DataManager : NSObject {
    NSMutableArray *eventList;
    NSMutableSet *favorites;
}

@property (nonatomic, retain) NSMutableArray *eventList;
@property (nonatomic, retain) NSMutableSet *favorites;

+(DataManager*)sharedDataManager;

@end

.m:

#import "DataManager.h"

static DataManager *singletonDataManager = nil;

@implementation DataManager

@synthesize eventList;
@synthesize favorites;

+(DataManager*)sharedDataManager {
    @synchronized(self) {
        if (!singletonDataManager) {
            singletonDataManager = [[DataManager alloc] init];
        }
    }
    return singletonDataManager;
}

- (DataManager*)init {
    if (self = [super init]) {
        eventList = [[NSMutableArray alloc] init];
        favorites = [[NSMutableSet alloc] init];
    }
    return self;
}

------EDIT EDIT EDIT EDIT------

At @TechZen's suggestion, I moved my accessor methods into the data manager singleton. Here's what it now looks like:

#import "DataManager.h"

static DataManager *singletonDataManager = nil;

@implementation DataManager

@synthesize eventList;
@synthesize favorites;

+(DataManager*)sharedDataManager {
    @synchronized(self) {
        if (!singletonDataManager) {
            singletonDataManager = [[DataManager alloc] init];
        }
    }
    return singletonDataManager;
}

- (DataManager*)init {
    if (self = [super init]) {
        eventList = [[NSMutableArray alloc] init];
        favorites = [[NSMutableSet alloc] init];
    }
    return self;
}


#pragma mark -
#pragma mark Data management functions

- (void)addToFavorites:(NSString *)guid
{
    [self.favorites addObject:guid];
    NSLog(@"Item added--we now have %d faves.", [favorites count]);
}

- (void)removeFromFavorites:(NSString *)guid
{
    [favorites removeObject:guid];
    NSLog(!"Item removed--we now have %d faves.", [self.favorites count]);
}


@end

I made my viewcontroller where this is happening call [[DataManager sharedManager] addToFavorites:Event.guid] instead of adding the item right to the favorites set itself, but I left the logging stuff that was there in place.

Here's my log:

2010-05-13 13:25:52.396 EverWondr[8895:207] Toggling on, adding 05db685f65e2
2010-05-13 13:25:52.397 EverWondr[8895:207] Item added--we now have 0 faves.
2010-05-13 13:25:52.398 EverWondr[8895:207] favorites array now contains 0 members
2010-05-13 13:25:53.578 EverWondr[8895:207] Toggling off
2010-05-13 13:25:53.579 EverWondr[8895:207] favorites array now contains 0 members

So.... the DataManager object can't even add anything to its own property! And it doesn't throw an exception like it would if it was a non-mutable type, it just silently fails!

Just for fun, I went through and changed it to an NSMutableArray, which I'm more familiar with. Same behavior.

+2  A: 
TechZen
Thanks. I'll make my way through this and apply it to my code. "guid" in this case (a web app whose code and database I'm inheriting) refers to a 12-character string coming to me from a MySQL database on the web server. I've looked at their code--there's nothing actually guaranteeing the uniqueness of it, it's just a biggish random number. Not ideal, but it's what I'm working with.
Dan Ray
Okay, re what I'm actually returning... I just used debug to step through my singleton's initializer. Examining the ivars of my DataManager object, I see that my favorites, which is initialized in init with `favorites = [[NSMutableSet alloc] init];` is actually getting created as a NSCFSet, and I don't know what that is nor what to make of it....
Dan Ray
The answer doesn't make sense to me. `NSMutableSet *favorites = data.favorites;` will not magically turn the set from a mutable set into an immutable set. The property is retain so it will return a reference to the same object that was allocated as a mutable set. Furthermore, if favorites was an immutable set, trying to add objects to it would throw an exception. The exception should appear in the log if it is happening.
JeremyP
See my edit for an explanation.
TechZen
By the way, I think both NSSet and NSMutableSet are really instances of NSCFSet with a flag to say if the set is mutable or not. Not hundred percent certain about that but will chweck later.
JeremyP
@techzen: "See my edit for an explanation" - sorry, still can't see it. Sending favorites to data unquestionably returns a reference to a mutable set. Assigning it to a local variable just sets that local variable to be a reference to the same mutable set.
JeremyP
FURTHER EDITS above. Curiouser and curiouser.
Dan Ray
I fell back and stuck this stuff in NSUserDefaults. It's just an array of strings, after all, and it IS, logically speaking, a user setting. So that works, but it doesn't clear up for my why this was happening.
Dan Ray