GeckoGeek.fr

Paradigme d'un lézard

Vendredi 31 Mars 2017

Créer un Singleton sur iPhone en Cocoa / Objective-C

Par Vinz le 26/01/2010 dans Apple, Programmation | 6 commentaires

Lorsque l’on a besoin d’un même objet à différents endroits il n’est pas nécessaire de le faire passer d’une classe parente à une classe enfant, et encore moins de lui allouer de la mémoire plusieurs fois. Une bonne solution consiste à transformer votre classe en un singleton. Voyons ainsi comment créer un singleton en objective-c pour iPhone (mais cela marche aussi sur Mac).

Qu’est-ce qu’un singleton ?

Un singleton est un design pattern qui a pour but de n’allouer de la mémoire qu’une fois pour un objet dans tout le programme. De même cet objet peut être atteint n’importe où dans le programme et ne nécessite pas d’être explicitement instancié avant d’être utilisé. Ce dernier utilisera à chaque appel la même instance ou la créera si c’est la première utilisation.

L’implémentation d’un singleton dans la plupart des langages est chose facile. Sur iPhone il est possible de faire la même chose, toutefois Apple préconise une certaine implémentation d’un singleton en cocoa. En voici un exemple tout cuit.

Nous prendrons l’exemple d’une classe “User” contenant toute sorte d’informations relatives à l’utilisateur courant. Mais c’est juste pour le nom puisque nous ne déclarerons pas tant de méthodes que ça.

Interface de la classe (.h)

Commençons par décortiquer le plus simple : l’interface de la classe. Comme notre exemple a pour but d’être simple, nous prendrons une méthode simple à comprendre. Notre utilisateur comporte une variable “points”. Cette variable peut être augmentée et affichée.

/*
 * User Interface, Singleton
 * Exemple de GeckoGeek.fr
 */

@interface User : NSObject {

	NSInteger points;

}
@property (nonatomic, assign) NSInteger points;
+ (User *)sharedUser;
- (void)addPoints:(NSInteger)nbr;

@end

User dérive d’un “NSObject” et contient une méthode “sharedUser” qui renverra l’objet instancié une seule fois au cours de la vie du programme. Et pour notre exemple nous avons la variable “points” qui est un NSInteger (== int en C) avec la méthode “addPoints” pour ajouter plus facilement des points.

Implémentation de la classe (.m)

Voyons maintenant comment implémenter la classe. Comme je le disais plus haut, Apple préconise une implémentation particulière d’un Singleton sur iPhone.

Variable static pour l’unique instanciation

Votre implémentation doit déjà contenir une variable static pour stocker l’unique instanciation de votre objet. Dans notre cas nous aurons quelque chose comme ceci :

static User *sharedUserManager = nil;

Méthodes à redéfinir

Ensuite un ensemble de méthodes sont à redéfinir et à laisser telles quelles dans votre implémentation :

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

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

- (id)retain {
    return self;
}

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

- (void)release {
    //do nothing
}

- (id)autorelease {
    return self;
}

Vous pourrez retrouver les même conseils sur le lien pointant sur Apple un peu plus haut.

Méthode d’accessibilité

Et enfin vous avez besoin de définir la méthode qui vous permettra d’accéder à l’objet ou que vous soyez.

+ (User*)sharedUser
{
    if (sharedUserManager == nil) {
        sharedUserManager = [[super allocWithZone:NULL] init];
    }
    return sharedUserManager;
}

Si vous la lisez bien vous verrez qu’elle fait le travail ordinaire d’un singleton. Si la variable static est nulle alors elle fait l’allocation unique et retourne le pointer.

Tout en un

Voici l’ensemble de l’implémentation de la classe user :

#import "User.h"

@implementation User

@synthesize points;

static User *sharedUserManager = nil;

-(id)init {

	if (self = [super init]) {

		// Init points to 0
		points = 0;

	}
	return self;

}

-(void)dealloc {

	// Do things
	[ super dealloc ];

}

////////////////////
// Singleton Methods
+ (User*)sharedUser
{
    if (sharedUserManager == nil) {
        sharedUserManager = [[super allocWithZone:NULL] init];
    }
    return sharedUserManager;
}

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

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

- (id)retain {
    return self;
}

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

- (void)release {
    //do nothing
}

- (id)autorelease {
    return self;
}

@end

Lors de l’init nous initialisons la variable “points” à 0. Il nous suffit de rajouter la méthode “addPoints”

Méthode “addPoints”

Exemple simple, méthode simple. Cette méthode ne fait que rajouter un nombre à la variable de l’instanciation.

-(void)addPoints:(NSInteger)nbr {

	points += nbr;

}

Exemple d’utilisation

Dans votre classe faites un “import” de la classe singleton. Dans notre exemple cela donnerait :

#import "User.h"

Puis pour utiliser votre classe il suffit d’écrire “[ User sharedUser ]” et appeler une variable ou une méthode. Concrètement pour ajouter des points il suffit d’écrire :

[ [ User sharedUser ] addPoints:5 ];

Et pour lire le nombre de points :

NSLog(@"Points=%d", [ [ User sharedUser ] points ]);

A vous maintenant d’ajouter vos propres méthodes et customiser votre singleton comme bon vous semble ! :-]

Commentaires (6)
  1. Alex le 31 Oct 2010 à 19:24

    Merci pour ces explications!!

  2. Dim le 10 Nov 2010 à 11:41

    Bien expliqué, grand merci.

  3. Vincent le 22 Mar 2011 à 11:06

    Merci pour cette explication, très clair.

  4. lamjed le 14 Apr 2011 à 12:04

    Thanks a lot for this interesting tutorial

  5. omnia69 le 20 Jul 2011 à 06:31

    Une petite explication simple et claire et bien structurée.
    Merci

  6. Antoine le 22 Jul 2011 à 08:40

    Très clair! merci!


Laisser un commentaire