Méthodes d'instances pour un singleton
colas_
Membre
Bonjour !
Je me rends compte que dans les singletons (en fait shared instances) que je crée, je ne mets en public interface pratiquement que des méthodes de classes !
Par exemple :
@interface MyCBDPurchasingManager : NSObject
+ (instancetype)purchasingManager ;
+ (BOOL)isPurchased:(MyObject *)myObject ;
@end
Ensuite, quand j'implémente ces méthodes, bien souvent j'ai en interne une méthode d'instance que j'appelle sur la shared instance.
@implementation MyCBDPurchasingManager
- (instancetype)init
{
self = [super init] ;
if (self)
{
_purchasedObjects = [NSMutableDictionary new] ;
}
return self ;
}
+ (instancetype)purchasingManager
{
static id _sharedInstance = nil ;
static dispatch_once_t onceToken;
dispatch_once(&onceToken,
^{
_sharedInstance = [[self alloc] init];
});
return _sharedInstance;
}
+ (BOOL)isPurchased:(MyObject *)obj
{
return [[self purchasingManager] isPurchased:obj];
}
- (BOOL)isPurchased:(MyObject *)obj
{
return [self.purchasedObjects[obj.id] boolValue] ;
}
@end
Est-ce que c'est une bonne pratique ? Est-ce ça change rien ?
Merci !
Colas
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Salut,
Je pense que c'est une bonne pratique. Tu peux même mettre la méthode purchasingManager en private ( dans l'extension de la classe) si tu as juste des méthodes de classe en public.
PS : Je ne sais pas si ton message est dans la bonne section ?
Il existe une solution alternative qui est de mettre à profit la méthode "+[NSObject forwardingTargetForSelector]" pour que tout message inconnu / non implémenté envoyé à ta classe soit forwardé à la sharedInstance.
Sauf qu'en pratique c'est nul car tu n'as plus d'aitocompletion, ainsi que des warnings partout concernant des méthodes que tu appelles qui n'existent pas d'après le ".h"... donc au final c'est aussi simple de faire comme tu fais.
Effectivement, on n'a même plus besoin de savoir que c'est une sharedInstance !
Et du coup quand tu as besoin d'accéder à des propriétés tu fais "self.purchasingManager.purchasedObjects" dans ta méthode "+ isPurchased" au lieu de faire "self.purchasedObjects" dans ta méthode "- isPurchased".
Franchement, il faut surtout arrêter avec les singletons à toutes les sauces. Qu'est-ce qui t'empêche d'instancier cet objet ? C'est pas comme si ça servait dans toute l'appli.
A part rendre le code moins lisible, je ne vois pas trop l'interet.
Quitte à ecrire des methodes statiques pour taper dans un objet global, autant mettre tes donnees en static dans le fichier .m. >:D
Ouais, et briser la garantie d'atomicité d'accès...
Tu vas me dire, la garantie d'atomicité d'accès d'une propriété ne garantit pas l'atomicité de tout le système, donc dans tous les cas il faut faire gaffe à ce genre de choses (cf l'excellente présentation de Andy Matuschak à Realm qui circule récemment sur Twitter) mais n'empêche...
@synchronized ?
De ce côté Swift va quand même pas mal changer la donne en tout cas :
- la plupart des cas où on fait une classe ne contenant que des méthodes de classe c'est pour avoir une certaine forme de namespace pour grouper les méthodes ensemble. Or contrairement à ObjC, Swift a déjà ce concept de namespace.
- le besoin d'un singleton en ObjC est aussi souvent à cause du manque de concept de variable de classe en ObjC. Swift 1.2 supporte les variables de classe et de struct.
- Pour le côté atomicité, l'utilisation des ValueTypes (utiliser struct plutôt que class typiquement) garantit que chaque ValueTypes n'a qu'un seul owner et que chaque instance est passée par copie. ça ne résoud pas tous les cas où l'atomicité est garantie mais ça évite pas mal de cas où elle est autrement nécessaire en ObjC.