Static NSArray of strings - how/where to initialize in a View Controller
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.
Alexander Farber
/me/likes: Java, С#, Perl, PHP, JavaScript, PostgreSQL, Linux, Azure /me/speaks: German, English, Russian /me/learns: https://github.com/afarber/android-questions https://github.com/afarber/unity-questions https://github.com/afarber/ios-questions
Updated on January 21, 2020Comments
-
Alexander Farber over 4 years
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
inawakeFromNib
(since I use stroyboard scenes for all my ViewControllers)? Or maybe ininitSomething
(is the correct methodinitWithStyle
?) -
jlehr over 10 yearsThat would mean every instance would have its own copy of the array. I don't think that's what the OP was looking for.
-
Simon McLoughlin over 10 yearsThe user is asking WHERE to create this, not how. You haven't provided any help, the users answer shows him trying to instantiate an object in an interface
-
jlehr over 10 years@SimonMcLoughlin Quoting the OP, "My question is however how to init the NSArray _titles?" [emphasis added]
-
Simon McLoughlin over 10 yearsfair enough, the point still stands that he's trying to instantiate the object in the interface, this would remove his xcode complier warnings, ill edit with a static array
-
jlehr over 10 yearsIf you look carefully, you'll see that the OP posted two different failed attempts, the first of which was an attempt to initialize a global constant with an
NSArray
. -
Simon McLoughlin over 10 years@jlehr and if you read the rest of the question you will see he is getting syntax warnings due to the above mentioned issue. The user is asking for a basic understanding of how to instantiate an object in the flow of a viewController object. Fair point your solution might be the best way to create it, but the user is quite clearly looking for info as to WHERE to create it
-
Hot Licks over 10 years@jlehr - How many instances of this view controller do you think there are going to be?
-
Simon McLoughlin over 10 years@HotLicks no that was a valid point, the user did clearly define a static array. The user more than likely had a reason for going out of there way to do that
-
Hot Licks over 10 years@SimonMcLoughlin - Can you say "premature optimization"?
-
Alexander Farber over 10 yearsThanks! This seems to be a runtime solution (instead of the compile-time that I was expecting) - is it the best choice for iOS?
-
Alexander Farber over 10 yearsIf I use viewDidLoad, then the _titles will be assigned again and again, when I press Home button to send the app to background and then bring it to foreground?
-
jlehr over 10 yearsObjects can't be allocated at compile time, so this is typically what we do. Note that
dispatch_once
is a Grand Central Dispatch function that ensures the code in the provided block is only run once in the lifetime of the app. -
Alexander Farber over 10 yearsThanks, but I've search and it seems (surprisingly!) that this method can be called more than once for a class - when an inheriting class does not implement own +initialize method.
-
Emmanuel over 10 years@AlexanderFarber Then check that _titles_1 is nil or for the current class in
+initialize
-
Alexander Farber over 10 yearsIf I check for
nil
- can't it happen that the+initialize
method runs once, but for a wrong class - for the inheriting class? -
gnasher729 over 10 years+initialize runs once for the class itself, and once for every subclass that doesn't override it. That's why you compare "if (self == [MyIntendedClass class])" first. The check for nil makes it necessary to use synchronisation because two subclasses could be initialised from different threads.
-
Emmanuel over 10 years@gnasher729
+initialize
is thread safe, according Apple documentation :The runtime sends the initialize message to classes in a thread-safe manner.
-
Brody Robertson over 9 yearsYou can use the fully qualified class name to call the static method. Instead of [[self class] titles] you can just call [MyClassName titles];
-
jlehr over 9 years@BrodyRobertson Targeting a specific instead of obtaining a reference to the class dynamically class breaks inheritance. Also, not sure what you mean by 'fully qualified' class name -- Objective-C doesn't provide namespaces for classes. Did you have something else in mind?
-
Brody Robertson over 9 years@jlehr a fully qualified name is an unambiguous name that specifies which object, function, or variable a call refers to without regard to the context of the call. I don't understand what you mean when you say calling a static method via it's qualified classname breaks inheritance.
-
Admin about 7 yearsSometimes, most always the simplest solution is not only the most effective, but the best... Being relatively new to Obj-C (7 years now) I'm still put off by the syntax, but I was pretty sure, a simple static array didn't need to involve 25 lines of code.. My C/C++ background told me this would probably work... NSString *dayNamesArray[7] = {@"blah",@"blah",@"blah",@"blah",@"blah",@"blah",@"and blah"}; I give you credit for the most common sense solution... Thanks!
-
jlehr about 6 yearsObjective-C class methods are not static -- they're dynamically dispatched exactly the same way instance methods are, are inherited, and can be overridden in subclasses.
-
Tiago Mendes almost 6 yearswith that code you get the error: "Initializer element is not a compile-time constant"