2012-01-19 6 views
5

He revisado (y probado) algunos de los hilos aquí con respecto a Singletons y NSMutableArrays. Soy nuevo en Objective-C así que por favor tengan paciencia conmigo.Forma correcta de crear/usar un Singleton NSMutableArray para Xcode 4

Simplemente quiero crear unas pocas matrices a las que se pueda acceder desde cualquier archivo de vista/.m.

¿Cuál es la mejor (o más concisa) codificación para un Singleton?

A continuación se muestra lo que tengo ahora y me da 1 de advertencia a .m '@implementation' - "Aplicación inadecuada" 1 error en el uso de un archivo de vista .m - "elemento inicializador no es una constante de tiempo de compilación "

Este es el código que tengo ahora - mi archivo GlobalData.h:

#import <Foundation/Foundation.h> 

@interface GlobalData : NSObject {  
    NSMutableArray *listOfHeadings; 
    NSMutableArray *listOfItems1; 
    NSMutableArray *listOfItems2; 
}  
@property(nonatomic,retain)NSMutableArray *listOfHeadings; 
@property(nonatomic,retain)NSMutableArray *listOfItems1; 
@property(nonatomic,retain)NSMutableArray *listOfItems2; 
+(GlobalData*)getInstance; 
@end 

mi archivo GlobalData.m:

#import "GlobalData.h" 

@implementation GlobalData 
@synthesize listOfHeadings; 
@synthesize listOfItems1; 
@synthesize listOfItems2; 
static GlobalData *instance=nil; 

+(GlobalData *)getInstance  
{  
    @synchronized(self)  
    {  
     if(instance==nil)  
     {  
      instance= [GlobalData new];  
     }  
    }  
    return instance;  
}  
@end 

Y en un archivo .m vista (simplificado):

#import GlobalData.h 

GlobalData *globDat=[GlobalData getInstance]; //error occurs here 

Puede alguien señalar el problema y si hay una mejor codificación, por favor me ilumine - gracias!

EDITAR

Aquí hay algunos enlaces que he tratado de usar:

Can i have a single NSMutableArray in my multiple views application?

iPhone help with singleton class

+0

Usar Matt Galaghers [singleton skeleton] (http://cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html). – Till

Respuesta

8

En este caso, usted podría estar haciendo más de lo que tiene que hacerlo. Ciertamente, esto no siempre es la mejor solución, pero puedes poner tu NSMutableArray como una propiedad en tu delegado de la aplicación y luego consultarla fácilmente desde cualquier punto de vista. Al hacerlo de esta manera, no lo está bloqueando como un 'singleton', pero hay una 'instancia única' (esto ayuda mucho para la capacidad de prueba).

He simplificado este proceso aquí:

YourAppDelegate.h

@property (nonatomic,retain) NSMutableArray *myArray; 

YourAppDelegate.m

@synthesize myArray; 

YourViewController.m

YourAppDelegate *appDelegate = (YourAppDelegate *)[[UIApplication sharedApplication] delegate]; 
NSMutableArray *myArrayFromAppDelegate = appDelegate.myArray; 

Desde este punto - y Puedes hacer cualquier manipulación en este valor.

+0

Lo he intentado algunas veces sin éxito. Aquí está el enlace http://stackoverflow.com/questions/8918396/how-to-share-a-variable-between-multiple-views-xibs – wayneh

+0

En este caso, si no está funcionando, se debe a una codificación error. Funciona. – dtuckernet

+0

Expandí este ejemplo de arriba. – dtuckernet

6

Aquí está la versión "moderna" de un solo método para convertir cualquier clase en una Singleton (en este caso formateado como un fragmento de código). Funciona en iOS4.x o superior:

+(<#SingletonClassName#> *) sharedInstance 
{ 
    static <#SingletonClassName#> *_sharedClient = nil; 

    static dispatch_once_t oncePredicate; 
    dispatch_once(&oncePredicate, ^{ 
     _sharedClient = [[self alloc] init]; 
    }); 

    return _sharedClient; 
} 

Pero, lo que realmente necesita un conjunto unitario de un solo NSMutableArray? Se podría utilizar el singleton construído sobre - el delegado de aplicación, que se llegó a llamar:

MyAppDelegate * appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate]; 
[appDelegate.myMutableArray addObject:...]; 
+0

¿Necesito un Singleton? No estoy seguro, he visto todo tipo de hilos y nunca hay acuerdo, algunos dicen que es mejor, otros no están de acuerdo ... He intentado con un código de llamada similar a lo que sugieres sin suerte. Ver este hilo: http://stackoverflow.com/questions/8918396/how-to-share-a-variable-between-multiple-views-xibs – wayneh

+0

No estoy hablando tanto de necesitar un singleton y elegir crear uno en lugar de simplemente usar el AppDelegate ya existente ... aunque también podría tener accesores para el arreglo mutable como un método de nivel de clase en una clase. En el enlace que publicó, una de las respuestas recomienda usar un singleton para administrar variables globales, como en plural ... si solo tiene una matriz flotando, no hay nada de malo en colocarla en el delegado de la aplicación a la que todo puede llegar fácilmente. –

+0

@KendallHelmstetterGelner Estoy casi en la misma situación. Necesito crear un 'NSMutableArray' (para diccionarios y cadenas), que pueda usar en 3-4 controladores de vista diferentes. Empecé a crear un singleton, pero no estoy seguro, es la idea más inteligente. He leído mucha opinión sobre el almacenamiento de datos en 'AppDelegate' pero es un poco confusa después de tu comentario. ¿Qué piensas, una matriz no le hará daño a nada? También tengo que poder cambiar su contenido de forma dinámica, en función de los datos descargados. Hasta ahora, la versión de 'AppDelegate' me parece más fácil. – rihe

3

Ésta es la manera Creo mi Singleton:

Singleton.h

#import <Foundation/Foundation.h> 

@interface Singleton : NSObject { 
    NSMutableArray *firstMutableArray; 
    NSMutableArray *secondMutableArray; 
} 

@property (nonatomic, retain) NSMutableArray *firstMutableArray; 
@property (nonatomic, retain) NSMutableArray *secondMutableArray; 

+ (id)sharedSingleton; 

@end 

Sigleton.m

#import "Singleton.h" 

static Singleton *sharedMySingleton = nil; 

@implementation Singleton 

@synthesize firstMutableArray; 
@synthesize secondMutableArray; 

#pragma mark Singleton Methods 

+ (id)sharedSingleton { 
    @synchronized(self) { 
    if (sharedMySingleton == nil) { 
     sharedMySingleton = [[super allocWithZone:NULL] init]; 
    } 
    return sharedMySingleton; 
} 

+ (id)allocWithZone:(NSZone *)zone { 
    return [[self sharedSingleton] retain]; 
} 

- (id)copyWithZone:(NSZone *)zone { 
    return self; 
} 

- (id)retain { 
    return self; 
} 

- (unsigned)retainCount { 
    return UINT_MAX; 
} 

- (oneway void)release { 
    // Never release 
} 

- (id)autorelease { 
    return self; 
} 

- (id)init { 
    if (self = [super init]) { 
     firstMutableArray = [[NSMutableArray alloc] initWithObjects:nil]; 
     secondMutableArray = [[NSMutableArray alloc] initWithObjects:nil]; 
    } 
    return self; 
} 

- (void)dealloc { 
    [firstMutableArray release]; 
    [secondMutableArray release]; 
    [super dealloc]; 
} 

@end 

Entonces, cuando usted quiere llamar a su Singleton:

#import "Singleton.h" 

Singleton *singleton = [Singleton sharedSingleton]; 
singleton.firstMutableArray = ... 
singleton.secondMutableArray = ... 
+0

Pero estás usando Singleton.h que es una clase creada por el usuario, ¿correcto? – wayneh

+0

Sí, lo es. Si tiene pocos NSMutableArray, probablemente no necesite una clase para administrarlos. Pero creo que una clase Singleton es un código más limpio: puedes agregar tantos objetos como quieras en cualquier momento y es reutilizable en cualquier proyecto. – Beppe

+0

Tendré que resolver esto ... Parece que los Singleton toman más código inicial, pero se implementan mucho más fácilmente. – wayneh

5

El error initializer element is not a compile-time constant no está relacionado con la forma en que crea su singleton. El error es cómo estás accediendo a tu singleton. Usted está haciendo esto fuera de una función:

GlobalData *globDat=[GlobalData getInstance]; 

Esto significa que usted está tratando de inicializar una variable global (globDat) como el valor de la expresión [GlobalData getInstance]. Solo puede inicializar variables globales a expresiones que son "constantes de tiempo de compilación". Eso significa cosas como 0 o "fred" o 8/2. El valor de [GlobalData getInstance] no se puede calcular en tiempo de compilación, por lo que no se puede utilizar para inicializar la variable global.

En su lugar, solo tiene que utilizar [GlobalData getInstance] dentro de los cuerpos de sus funciones donde quiera que intente utilizar la variable globDat actualmente.

En cuanto a la advertencia, Incomplete implementation, no veo lo que falta. Tal vez no publicó todo el código de GlobalData.h. De todos modos, debería poder hacer clic en la advertencia (donde aparece en el lado derecho de la ventana del editor) y hacer que Xcode le muestre lo que falta.

+0

Gracias - tenías razón, no estaba en un método. Ahora funciona. ¿Cómo comparto el crédito por la respuesta ya que dtuckernet a continuación también proporcionó una respuesta correcta? – wayneh

+0

Solo puede aceptar una respuesta por pregunta. Pero puedes votar cualquier número de respuestas. –

+0

Lo siento, para molestarlo, pero ahora que tengo el Singleton en funcionamiento, parece que no puedo modificar mi matriz. No recibo ningún error o advertencia del compilador. Mis esfuerzos 'addObject' no parecen hacer nada. – wayneh

Cuestiones relacionadas