ios - NSArray estático de cadenas: cómo/dónde inicializar en un controlador de visualización
objective-c nsmutablearray (8)
Deberías declarar tu matriz estática arriba @implementation
.
static NSArray *titles_1 = nil;
@implementation ...
Y awakeFromNib
en init
o awakeFromNib
o cualquier otro método como viewDidLoad
, applicationDidFinishLaunching
donde quieras.
- (void)initMethod{ //change the method name accordingly
if (titles_1 == nil){
[self setTitles_1:@[ @"Your Move", @"Their Move", @"Won Games", @"Lost Games", @"Options" ]];
}
}
En una aplicación de detalles maestros me gustaría mostrar un TableView con 5 secciones tituladas:
- Su movimiento
- Su movimiento
- Juegos ganados
- Juegos perdidos
- Opciones
Así que creo una aplicación Master-Detail en blanco en Xcode 5.0.2 y luego en su MasterViewController.m (que es un UITableViewController) estoy tratando de implementar el método:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return _titles[section];
}
Mi pregunta es, sin embargo, cómo iniciar los NG_títulos de NSArray.
Lo estoy intentando en 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
{
....
}
pero ambos intentos anteriores me dan errores de sintaxis:
ACTUALIZAR:
Para mi sorpresa, hay muchas sugerencias para esta simple pregunta, pero como novato iOS / Objective-C no estoy seguro, qué solución es la más adecuada.
dispatch_once
: ¿no es una operación en tiempo de ejecución ejecutar algo una vez en una aplicación de subprocesos múltiples? ¿No es excesivo aquí? Esperaba una solución en tiempo de compilación para iniciar una matriz de const ...
viewDidLoad
: cuando mi aplicación cambia entre el fondo y el primer plano, ¿no sería innecesario iniciar mi matriz de const una y otra vez?
¿No debería configurar mejor el NSArray
en awakeFromNib
(ya que uso escenas de stroboard para todos mis ViewControllers)? O tal vez en initSomething
(¿es el método correcto initWithStyle
?)
Escriba un método de clase que devuelva la matriz.
+ (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;
}
Entonces puedes acceder a él cuando sea necesario, así:
NSArray *titles = [[self class] titles];
Me pregunto si la siguiente sería una buena manera (respondiendo mi propia pregunta):
#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 esta forma, el const NSArray
se inicia una vez y justo antes de que lo necesite (en la clase MasterViewController
). Y la self
evita que este método se ejecute nuevamente, cuando alguna clase que hereda no implementa su propio método +initialize
.
No puede instanciar objetos de esta manera, solo puede declararlos en interfaces. Haz lo siguiente:
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
- o del mismo modo, podrías usar el método init viewcontroller en lugar de viewDidLoad
Prefiero usar Objective-C ++, cambiar el nombre de archivo de xxx.m
a xxx.mm
, y la inicialización de NSArray ocurrirá en tiempo de ejecución
sin dispatch_once
, no hay método de clase, solo escríbelo en una línea:
static NSArray *const a = @[@"a",@"b",@"c"];
Puedes iniciarlo en el método de clase +initialize
static NSArray *_titles_1;
@implementation MasterViewController
+ (void)initialize {
_titles_1 = @[
@"Your Move",
@"Their Move",
@"Won Games",
@"Lost Games",
@"Options"
];
}
@end
También puedes hacer algo como esto:
static NSString * const strings[] = {
[0] = @"string_1",
[1] = @"string_2",
[2] = @"string_3",
[3] = @"string_4",
// ...
};
No es un NSArray
pero puedes acceder a NSStrings
como este strings[n]
dispatch_once funciona. Funciona en casos complicados, y funciona en casos simples. Entonces, para ser coherente, lo mejor es usarlo en todos los casos. Eso hace, por ejemplo, mucho más fácil cuando reemplaza todas las cadenas constantes con llamadas a NSLocalizedString (). No es necesario cambiar el código.
Hacer cosas en + (nulo) initialize no es realmente incorrecto, pero he tenido situaciones en las que primero quería configurar una clase antes de usarla realmente, y la inicialización se llama, por supuesto, justo antes de que se inicie la ejecución de cualquier posible método de configuración. Y hay situaciones en las que realmente no tienes un contexto de clase. dispatch_once siempre funcionará.