views:

6858

answers:

5

Hey folks - I'm writing a pretty simple iPhone application. The data comes from a plist file (NSDictionary basically), that I'm trying to load into a singleton class and use across my various view controllers to access the data.

Here's the implementation for my singleton (heavily modeled after this thread)

@implementation SearchData

@synthesize searchDict;
@synthesize searchArray;

- (id)init {
    if (self = [super init]) {
     NSString *path = [[NSBundle mainBundle] bundlePath];
     NSString *finalPath = [path stringByAppendingPathComponent:@"searches.plist"];
     searchDict = [NSDictionary dictionaryWithContentsOfFile:finalPath];
     searchArray = [searchDict allKeys];
    }

    return self;
}

- (void)dealloc {
    [searchDict release];
    [searchArray release];
    [super dealloc];
}

static SearchData *sharedSingleton = NULL;

+ (SearchData *)sharedSearchData {
    @synchronized(self) {
     if (sharedSingleton == NULL)
      sharedSingleton = [[self alloc] init];
    } 
    return(sharedSingleton);
}

@end

So whenever I try to access the searchDict or searchArray properties elsewhere in my application (like a TableView delegate) like so:

[[[SearchData sharedSearchData] searchArray] objectAtIndex:indexPath.row]

I get an exception stating *** -[NSCFSet objectAtIndex:]: unrecognized selector sent to instance 0x5551f0

I'm not really sure why the objectAtIndex message is being sent to an NSCFSet object, I feel like my singleton is implemented wrong or something. I also tried a more complex singleton implementation like the one recommended by apple in the aforementioned thread and had the same problem. Thanks for any insight you can provide.

+8  A: 

In your -init method you are directly accessing your instance variables and you are not retaining them. They're getting deallocated and their memory is being used up by other objects later on in your application's lifetime.

Either retain your objects that you're creating there or use the non-convenience methods to generate them.

searchDict = [[NSDictionary alloc] initWithContentsOfFile:finalPath];
searchArray = [[searchDict allKeys] retain];
Ashley Clark
Thanks Ashley, retaining the variables fixed it. As a follow up - what is the purpose of (non-atomic, retain) in my @property declaration. I assumed retain meant the properties would automatically be retained.
Andy Bourassa
The tags in the @property definition define how the accessors work. In the case of (non-atomic, retain) they do not synchronize across multiple threads and they retain the object being assigned (which is atomic by nature anyway IIRC). You were directly assigning the variables though, bypassing them.
Ashley Clark
See my comment on the other answer about why you shouldn't be using the self.variable syntax in your -init and -dealloc methods though. Short-answer: unwanted side-effects.
Ashley Clark
A: 

Whenever you assign synthesized variables, do it through 'self', so:

- (id)init {
  if (self = [super init]) {
      NSString *path = [[NSBundle mainBundle] bundlePath];
      NSString *finalPath = [path stringByAppendingPathComponent:@"searches.plist"];
      self.searchDict = [NSDictionary dictionaryWithContentsOfFile:finalPath];
      self.searchArray = [searchDict allKeys];
  }

  return self;

}

Also make sure you've set up those variables to be 'retain'ed in the header file.

Chris Jefferson
Apple specifically advises against that in -init methods because your setters may have side-effects with conditions that aren't met yet during object initialization.
Ashley Clark
I should also add they advise against it in -dealloc also for the same reasons.
Ashley Clark
A: 

Hi,

Can you tell me what is the advantage, when we assign synthesized variables through 'self'?

Thank you shiva

A: 

Hi, Can you tell me what is the advantage, when we assign synthesized variables through 'self'? Thank you shiva

the values are set through the setter; it releases the previous value and retains the one you assign.

SorinA.
A: 

I made a reusable singleton class from which you can inherit to get singleton properties. You can see source code here: http://www.devbypractice.com/reusable-singleton-class-in-objective-c-for-iphone-and-ipad/

jey350