2010-10-27 5 views
2

Donc, je suis encore un peu nouveau sur Objective-C, et c'était ma première application que je suis en train de mettre à jour. L'idée est la suivante: L'ensemble de l'application est essentiellement différentes listes de choses. Il demande à l'API pour 15 messages, montre ceux avec un bouton Load More. Cliquez sur Charger plus, il en charge 15 de plus, etc. L'API à partir de laquelle il les charge dispose d'un système de jeton avec un délai d'expiration intégré. Trop long entre les demandes, et vous devez obtenir un nouveau jeton. Donc, je veux avoir un singleton à utiliser n'importe où dans mon application, donc je peux juste faire [APIMachine getToken] et dans les coulisses, il vérifie si le temps écoulé depuis la dernière demande était trop long (ou c'est la première demande), si oui, obtient un nouveau jeton, sinon renvoie celui que nous avons déjà. Je suis le modèle singleton que j'ai trouvé dans tant d'endroits, mais chaque fois que le bouton Charger plus utilise [APIMachine getToken] il ne reçoit rien ou quelque chose de complètement aléatoire. Je l'ai fait imprimer ces choses dans les journaux, et une fois j'ai même obtenu un UITableViewCell comme mon jeton. On dirait que les variables sont écrasées d'une manière ou d'une autre. Mais je ne peux vraiment pas le comprendre.iOS Singleton Variables ne gardant pas leurs valeurs

Alors voici:

static PoorAPI2 *_instance; 
@implementation PoorAPI2 

@synthesize apiToken, timeOpened, tokenTTL; 

+ (PoorAPI2*)sharedAPI 
{ 

    @synchronized(self) { 
     if (_instance == nil) {   
      _instance = [[super allocWithZone:NULL] init]; 
     } 
    } 
    return _instance; 
} 

-(NSString *)API_open{ 

    //boring code to get api token redacted 

if ([doneness isEqualToString:@"success"]) { 
    NSDictionary *data = [json objectForKey:@"data"]; 
    apiToken = [data objectForKey:@"api_token"]; 
    tokenTTL = [data objectForKey:@"ttl"]; 
    timeOpened = [NSDate date]; 

}else{ 
    NSLog(@"FFFFFFFUUUUUUUUUUUU this error should be handled better."); 
} 

return apiToken;  
} 

-(BOOL)isConnectionOpen{ 
    return ([timeOpened timeIntervalSinceNow] > tokenTTL); 
} 

-(NSString *)getToken{ 
    if([self isConnectionOpen]){ 
     return apiToken; 
    }else{ 
     return [_instance API_open]; 
    } 
} 

-(id)init{ 
    if(self = [super init]){ 
     apiToken = [[NSString alloc] initWithString:@""]; 
     timeOpened = [[NSDate alloc] initWithTimeIntervalSinceNow:0]; 
     tokenTTL = 0; 
    } 
    return self; 
} 

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

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

- (id)retain 
{ 
    return self;  
} 

- (unsigned)retainCount 
{ 
    return NSUIntegerMax; //denotes an object that cannot be released 
} 

- (void)release 
{ 
    //do nothing 
} 

- (id)autorelease 
{ 
    return self;  
} 

@end 

Je ne peux qu'espérer que je fais quelque chose sérieusement stupide et ce sera un fil hilarante pointer-rire-à-ce-type. Alors au moins mon application va fonctionner.

Répondre

2

Dans API_open, vous stockez trois objets dans des variables d'instance, mais ils ne sont pas des objets que vous possédez, ils seront donc probablement supprimés au moment où vous en avez besoin et remplacés par quelque chose d'imprévisible. Vous devez les conserver ou utiliser les setters appropriés.

+0

Ça fait tellement plus de sens, merci. – pettazz

+1

J'ai rencontré le même problème - Je suppose que la leçon à retenir ici est d'utiliser des setters et getters avec NSStrings, au lieu de l'opérateur d'affectation dans Objective-C. –

0

problème est la suivante:

static PoorAPI2 *_instance; 

C, et par Objective-C l'héritage, n'initialise pas les variables. Il suffit de changer pour:

static PoorAPI2 *_instance = nil; 

Je suis aussi de l'école que l'ajout de code supplémentaire pour essayer d'empêcher le singleton d'être utilisé comme unique est une perte de temps, et seulement vous donner plus de code avec plus de possibilités pour bogues.

Donc si j'étais vous alors je supprimerais toutes les méthodes de +[PoorApi2 allocWithZone:] et vers le bas. Objective-C est un langage dynamique et si un client voulait instancier une deuxième instance de votre singleton alors il serait capable de le faire malgré toutes vos lignes de code supplémentaires gaspillées. Au plus j'ajouter un journal comme celui-ci:

-(id)init{ 
    if (_instance) NSLog(@"WARNING: PoorAPI2 already has a shared instance."); 
    if(self = [super init]){ 
     apiToken = [[NSString alloc] initWithString:@""]; 
     timeOpened = [[NSDate alloc] initWithTimeIntervalSinceNow:0]; 
     tokenTTL = 0; 
    } 
    return self; 
} 

Créer une seconde instance d'un singleton est une erreur de programmation et doit être pris dans le développement. Pas de problème, vous devriez ajouter des lignes de code supplémentaires à cacher.

+3

Votre commentaire sur les variables statiques est incorrect. Ils sont initialisés à 0. Seules les variables automatiques doivent être explicitement initialisées. – Chuck

Questions connexes