开发者

How can I use an NSArray as a global constant?

I'm using a set of Constant.m files, one per target, to define specific things for each target. For example:

// Constants.h
extern NSString * const kDatabaseFileName;
//Constants.m
NSString * const kDatabaseFileName = @"target_one.sql开发者_如何转开发ite";

I'd also like to define an NSArray for each of my targets:

NSArray * const kLabelNames = [[NSArray alloc] initWithObjects:
    @"nameLabel", @"addressLabel", nil];

But this gives "error: initializer element is not constant". Using 'arrayWithObjects` doesn't work either. Is this because the strings in my array are not constants?

How can I set up an array as a global constant? Thanks.


In Objective-C, objects can only be allocated in heap, so there's no way to create an NSArray in static memory. However, you can create a C array of pointers to NSString constants like so...

NSString * const kLabelNames[] = {
    @"Foo", @"Bar", @"Baz"
};

...and then you can write class methods like this one...

+ (NSArray *)labelNames
{
    static NSArray *names;
    if (names == nil) {
        names = [[NSArray alloc] initWithObjects:kLabelNames count:3];
    }
    return names;
}

Edit

Note that with the introduction of new technologies such as ARC, Grand Central Dispatch and the new literal syntax for arrays, there's now a more straightforward way to accomplish something similar. Note that the example below also provides greater thread safety, though the original example could have incorporated an @synchronized block, or one of several other mechanisms, to achieve similar results.

+ (NSArray *)labelNames
{
    static NSArray *names;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        names = @[@"Foo", @"Bar", @"Baz"];
    });

    return names;
}

However the above example doesn't completely address the original question though. If a global constant array is truly needed, the preceding example could be rewritten along similar lines as the original answer, while still taking advantage of GCD:

NSString * const kLabelNames[] = {
    @"Foo", @"Bar", @"Baz"
};

+ (NSArray *)labelNames
{
    static NSArray *names;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        names = [NSArray arrayWithObjects:kLabelNames count:3];
    });

    return names;
}


Here's a much simpler approach:

Declare NSString with comma separated elements (or whatever delimiter you want)

NSString *const kLabelNames = @"Foo,Bar,Baz";

Then convert to NSArray whenever you need it:

NSArray *namesArray = [kLabelNames componentsSeparatedByString:@","];


If you want a set of constants that includes NS types, consider placing them all in a singleton.

You could have a single header file, and multiple implementation files (one per target). As long as that all implement the class declared in the header file you should be fine.


Use a macro:

#define SOME_ARRAY (@[@"blah", @"asdf", @"qwerty"])


You should create a class that contains the constants in class methods. Then you can add the class to whatever target and call the methods to get constants in objects like arrays. Vary the class or the class implementation to change the return of the constants.

If you use it a lot, you can create a protocol that defines the method names. Then swap out the class that implements the protocol in each target so that the same code returns different values as need.


If you want to avoid doing a NULL check on each usage, you can subclass the NSObject +initialize method. That will get called once, the first time your class is instantiated (and once more per subclass, if any subclasses are instantiated), and is a very good place to do this sort of initialization.

http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/Reference/Reference.html%23//apple_ref/occ/clm/NSObject/initialize

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜