Static NSArray of strings - how/where to initialize in a View Controller
In a Master-Detail app I'd like to display a TableView with 5 sections titled:
- Your Move
- Their Move
- Won Games
- Lost Games
- Options
So I create a blank Master-Detail app in Xcode 5.0.2 and then in its MasterViewController.m (which is a UITableViewController) I'm trying to implement the method:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return _titles[section];
}
My question is however how to init the NSArray _titles?
I'm trying in the MasterViewController.m:
#import "MasterViewController.h"
#import "DetailViewController.h"
static NSArray *_titles_1 = @[
@"Your Move",
@"Their Move",
@"Won Games",
@"Lost Games",
@"Options"
];
@interface MasterViewController () {
NSMutableArray *_games;
NSArray *_titles_2 = @[
@"Your Move",
@"Their Move",
@"Won Games",
@"Lost Games",
@"Options"
];
}
@end
@implementation MasterViewController
- (void)awakeFromNib
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
self.clearsSelectionOnViewWillAppear = NO;
self.preferredContentSize = CGSizeMake(320.0, 600.0);
}
[super awakeFromNib];
}
- (void)viewDidLoad
{
....
}
but both tries above give me syntax errors:
UPDATE:
To my surprise there are many suggestions for this simple question, but as an iOS/Objective-C newbie I'm not sure, which solution is most appropriate.
dispatch_once
- isn't it a runtime operation to execute something once in a multi-threaded app? Isn't it overkill here? I was expecting a compile-time solution for initiating a const array...
viewDidLoad
- when my app changes between background and foreground, wouldn't it unnecessary initiate my const array again and again?
Shouldn't I better set the NSArray
in awakeFromNib
(since I use stroyboard scenes for all my ViewControllers)? Or maybe in initSomething
(is the correct method initWithStyle
?)
Solution 1:
Write a class method that returns the array.
+ (NSArray *)titles
{
static NSArray *_titles;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_titles = @[@"Your Move",
@"Their Move",
@"Won Games",
@"Lost Games",
@"Options"];
});
return _titles;
}
Then you can access it wherever needed like so:
NSArray *titles = [[self class] titles];
Solution 2:
You can init it in class method +initialize
static NSArray *_titles_1;
@implementation MasterViewController
+ (void)initialize {
_titles_1 = @[
@"Your Move",
@"Their Move",
@"Won Games",
@"Lost Games",
@"Options"
];
}
@end
Solution 3:
You should declare your static array above @implementation
.
static NSArray *titles_1 = nil;
@implementation ...
And define it in init
or awakeFromNib
or any other method like viewDidLoad
, applicationDidFinishLaunching
wherever you want.
- (void)initMethod{ //change the method name accordingly
if (titles_1 == nil){
[self setTitles_1:@[ @"Your Move", @"Their Move", @"Won Games", @"Lost Games", @"Options" ]];
}
}
Solution 4:
You can also do something like this:
static NSString * const strings[] = {
[0] = @"string_1",
[1] = @"string_2",
[2] = @"string_3",
[3] = @"string_4",
// ...
};
It's not an NSArray
but you can access NSStrings
like this strings[n]
Solution 5:
I wonder, if the following would be a good way (answering my own question):
#import "MasterViewController.h"
#import "DetailViewController.h"
static const NSArray *_titles;
@interface MasterViewController () {
NSMutableArray *_objects;
NSMutableArray *_yourMove;
NSMutableArray *_theirMove;
NSMutableArray *_wonGames;
NSMutableArray *_lostGames;
NSMutableArray *_options;
}
@end
@implementation MasterViewController
+ (void)initialize
{
// do not run for derived classes
if (self != [MasterViewController class])
return;
_titles = @[
@"Your Move",
@"Their Move",
@"Won Games",
@"Lost Games",
@"Options"
];
}
This way the const NSArray
is initalized once and right before I need it (in the MasterViewController
class). And the self
check prevents this method from running again - when some inheriting class does not implement its own +initialize
method.