Dans une application Master-Detail, je voudrais afficher une TableView avec 5 sections intitulées:
Je crée donc une application Master-Detail vierge dans Xcode 5.0.2 puis dans son MasterViewController.m (qui est un UITableViewController) j'essaie d'implémenter la méthode:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return _titles[section];
}
Ma question comment faire pour initier les _titres NSArray?
J'essaye dans le 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
{
....
}
mais les deux essais ci-dessus me donnent des erreurs de syntaxe:
MISE À JOUR:
À ma grande surprise, il existe de nombreuses suggestions pour cette question simple, mais en tant que débutant iOS/Objective-C, je ne sais pas quelle solution est la plus appropriée.
dispatch_once
- n'est-ce pas une opération d'exécution d'exécuter quelque chose une fois dans une application multi-thread? N'est-ce pas exagéré ici? Je m'attendais à une solution au moment de la compilation pour lancer un tableau const ...
viewDidLoad
- lorsque mon application passe de l'arrière-plan au premier plan, ne serait-il pas inutile de lancer mon tableau const à plusieurs reprises?
Ne devrais-je pas mieux définir le NSArray
dans awakeFromNib
(puisque j'utilise des scènes stroyboard pour tous mes ViewControllers)? Ou peut-être dans initSomething
(est la bonne méthode initWithStyle
?)
Écrivez une méthode de classe qui renvoie le tableau.
+ (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;
}
Ensuite, vous pouvez y accéder où vous en avez besoin, comme suit:
NSArray *titles = [[self class] titles];
Vous pouvez l'initier dans la méthode de classe + initialize
static NSArray *_titles_1;
@implementation MasterViewController
+ (void)initialize {
_titles_1 = @[
@"Your Move",
@"Their Move",
@"Won Games",
@"Lost Games",
@"Options"
];
}
@end
Vous pouvez également faire quelque chose comme ceci:
static NSString * const strings[] = {
[0] = @"string_1",
[1] = @"string_2",
[2] = @"string_3",
[3] = @"string_4",
// ...
};
Ce n'est pas un NSArray
mais vous pouvez accéder à NSStrings
comme ceci strings[n]
Vous devez déclarer votre tableau statique au-dessus de @implementation
.
static NSArray *titles_1 = nil;
@implementation ...
Et définissez-le dans init
ou awakeFromNib
ou toute autre méthode comme viewDidLoad
, applicationDidFinishLaunching
où vous voulez.
- (void)initMethod{ //change the method name accordingly
if (titles_1 == nil){
[self setTitles_1:@[ @"Your Move", @"Their Move", @"Won Games", @"Lost Games", @"Options" ]];
}
}
Je me demande si ce qui suit serait un bon moyen (répondant à ma propre 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"
];
}
De cette façon, le const NSArray
est initialisé une fois juste avant que j'en ai besoin (dans la classe MasterViewController
). Et la vérification self
empêche cette méthode de s'exécuter à nouveau - lorsqu'une classe héritant n'implémente pas sa propre +initialize
méthode.
dispatch_once fonctionne. Cela fonctionne dans des cas compliqués et cela fonctionne dans des cas simples. Donc pour être cohérent, le mieux est de l'utiliser dans tous les cas. Cela rend par exemple beaucoup plus facile lorsque vous remplacez toutes vos chaînes constantes par des appels à NSLocalizedString (). Aucun changement de code nécessaire.
Faire des choses dans + (void) initialize n'est pas vraiment mal, mais j'ai eu des situations où je voulais d'abord configurer une classe avant de vraiment l'utiliser, et initialize est bien sûr appelé juste avant qu'une méthode de configuration possible ne commence à s'exécuter. Et il y a des situations où vous n'avez pas vraiment de contexte de classe. dispatch_once fonctionnera toujours.
Vous ne pouvez pas instancier des objets de cette manière, vous ne pouvez les déclarer que dans des interfaces. Procédez comme suit:
static NSArray *_titles_2;
@interface MasterViewController () {
NSMutableArray *_games;
}
@end
@implementation MasterViewController
-(void)viewDidLoad()
{
_titles_2 = @[
@"Your Move",
@"Their Move",
@"Won Games",
@"Lost Games",
@"Options"
];
}
@end