简体   繁体   中英

Objective-C static field issue

I've created a small class that loads dictionary items from a plist file. The getSettingForKey method works the first time I call the static method, however after a few more calls the dictionary throws a SIGABRT exception for a call with the same key that worked on a previous call. Any ideas?

static NSDictionary *dictionary = nil;
static NSLock *dictionaryLock;

@implementation ApplicationSettingsHelper

+ (void) initialize
{
    dictionaryLock = [[NSLock alloc] init];

    // Read plist from application bundle.
    NSString *path = [[NSBundle mainBundle] bundlePath];
    NSString *finalPath = [path stringByAppendingPathComponent:@"Xxxx.plist"];
    dictionary = [NSDictionary dictionaryWithContentsOfFile:finalPath];

    // dump the contents of the dictionary to the console.
    for(id key in dictionary)
    {
        NSLog(@"bundle: key=%@, value=%@", key, [dictionary objectForKey:key]);
    }
}

+ (NSDictionary *)dictionaryItems 
{
    [dictionaryLock lock];

    if (dictionary == nil)
    {
        [self initialize];
    }

    [dictionaryLock unlock];

    return dictionary;
}

+(id)getSettingForKey:(NSString *)key
{        
    return [[self dictionaryItems] objectForKey:key];
}

@end

Moshe - I've taken your suggestion and updated to use NSUserDefaults instead:

+ (void)load 
{   
    // Load the default values for the user defaults    
    NSString* pathToUserDefaultsValues = [[NSBundle mainBundle]
                                          pathForResource:@"Xxxx" 
                                          ofType:@"plist"];

    NSDictionary* userDefaultsValues = [NSDictionary dictionaryWithContentsOfFile:pathToUserDefaultsValues];

    // Set them in the standard user defaults
    [[NSUserDefaults standardUserDefaults] registerDefaults:userDefaultsValues];
}

+ (id)getSettingForKey:(NSString *)key
{        
    return [[NSUserDefaults standardUserDefaults] valueForKey:key];
}

Your dictionary has probably been deallocated, causing an invalid memory access. When you create a dictionary using the dictionaryWithContentsOfFile: method, it is autoreleased, which means it will automatically be released in the future. Since you never retain the dictionary, that release will cause the dictionary to be deallocated.

Also, most of your dictionaryItems method is useless.

[dictionaryLock lock];
if (dictionary == nil) {
    [self initialize];
}
[dictionaryLock unlock];

The +initialize method is automatically called by the runtime before any other method is called on your class, unless you have a +load method. Since the runtime will call it for you and it will attempt to create the dictionary, the dictionary can only be nil in the dictionaryItems method if there wasn't enough memory to create it, in which case it will fail again. Also, if you don't use the lock anywhere else, it is unnecessary also, since removing that check would cause it to be locked and immediately unlocked. Therefore, you can remove the lock and change your dictionaryItems method to simply:

+ (NSDictionary *)dictionaryItems {
    return dictionary;
}

In addition to @ughoavgfhw's answer, you are also initializing dictionaryLock after you are locking it. Unless you are initializing dictionaryLock somewhere else, I'm surprised your code is getting as far as it is.

Edit: I see from @ughoavgfhw's edit that +initialize is called before anything else, so your lock is initialized there.

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