Using a constant NSString as the key for NSUserDefaults

50,068

Solution 1

You should use:

NSString * const kPolygonNumberOfSides = @"..."; // const pointer

instead of:

NSString const * kPolygonNumberOfSides = @"..."; // pointer to const

The first is a constant pointer to an NSString object, while the second is a pointer to a constant NSString object.

It is a subtle difference. The compiler warning happens because setObject:forKey: is declared as follows:

- (void)setObject:(id)value forKey:(NSString *)defaultName;

It is expecting the defaultName argument to be of type NSString *. When you instead pass in a pointer to a constant, you've given it something different.

Update: I want to point out that these constants should be defined as static if they are only going to be used from within a single file. I say this because I have run across this problem myself: if you do not declare them as static, then they will exist in the global namespace, and you will not be able to use a variable with the same the same name in another file. see Constants in Objective-C for more information. To explain by example, this is what I currently use for keys that I only need to use in one .m file:

static NSString * const kSomeLabel = @"...";

Solution 2

Don't use const with Objective-C objects, they weren't really designed to use it. NSString objects (among many others) are already immutable by default by virtue of their design, so making them const is useless.

As e.James suggested, you can use an NSString * const, which is a constant pointer to an NSString. This is subtly different from a const NSString * (equivalent to NSString const *), which is a pointer to a constant NSString. Using a NSString * const prevents you from reassigning kPoly to point to a new NSString object.

Solution 3

For access from other classes:

.h

extern NSString * const PolygonNumberOfSidesPrefsKey;

.m

NSString * const PolygonNumberOfSidesPrefsKey = @"PolygonNumberOfSides"

For access only inside current class:

.m

static NSString * const kPolygonNumberOfSidesPrefsKey = @"PolygonNumberOfSides"

Solution 4

I would suggest even making the constant more descriptive. A constant for the number of sides of a polygon could come from anywhere. As a suggestion, how about:

kDefaultsPolygonNumberOfSides;

instead.

Share:
50,068
Olly
Author by

Olly

Software Engineer @ New Bamboo.

Updated on July 08, 2022

Comments

  • Olly
    Olly almost 2 years

    I'm using NSUSerDefaults to store user preferences. I remember reading somewhere that setting the keys as constants is a good idea - and I agree. The following code is what I currently have:

    [[NSUserDefaults standardUserDefaults]
            setObject:[NSNumber numberWithInt:polygon.numberOfSides] 
               forKey:@"polygonNumberOfSides"];
    

    I tried changing this to:

    @implementation Controller
    
    NSString const *kPolygonNumberOfSides = @"polygonNumberOfSides";
    
    -(void)savePolygonInfo {
        [[NSUserDefaults standardUserDefaults]
                setObject:[NSNumber numberWithInt:polygon.numberOfSides] 
                   forKey:kPolygonNumberOfSides];
    }
    

    While this does work, it produces "warning: passing argument 1 of 'objectForKey:' discards qualifiers from pointer target type". I'm keen to keep my code free from compiler warnings. How can I fix this warning?

  • Mathias
    Mathias about 15 years
    Good point about the use of const. That's why a lot of Objective-C classes have "Mutable" variants.
  • Dan Rosenstark
    Dan Rosenstark over 13 years
    I thought that const also means you can't reassign it. I guess I had that wrong.
  • Ternary
    Ternary over 8 years
    NSString * const foo works because NSString is immutable and the pointer is immutable so it can never change correct? Also, I recall from C++ that const is implicitly static (a compiler optimization) so no need to call it out. Is that true here as well?
  • vegashacker
    vegashacker about 3 years
    Given your 2nd paragraph, I think you should amend your first paragraph. Not being able to reassign an identifier is a valid use, and doesn't really have anything to do with mutability of the object itself. If you declare an NSString as NSString* const foo = @"bar" and then later try to reassign it, you'll get the error Cannot assign to variable 'foo'... which is exactly what I'd hope for when declaring something const.