I have an object which is initiated in my nib file. I want it to be a singleton but also accessible from code through [myClass sharedInstance];. Right now I have this:
static myClass *singleton = nil;
#implementation myClass
+ (myClass *)sharedInstance
{
if (!singleton) singleton = [[self class] new];
return singleton;
}
+ (id)alloc
{
return [self sharedInstance];
}
- (id)init
{
if ([self class] != nil)
self = [super init])
return self;
}
#end
But alloc never gets called.
Solved. See the end of http://www.cocoadev.com/index.pl?SingletonDesignPattern
Related
I have a Gamehud where I want to display an object's name. There are lots of objects/sprites in main scene what I am trying to do is to display selected(on touch) objects' name on Gamehud.
Problem is if I alloc Gamehud in CCsprite class it creates new instance and does not update current Gamehud. If I use something like GameHUD *gamehud= (GameHUD *)[self.parent getChildByTag:99]; nothing happens I cannot send the object to GameHud class.
So what would be the correct way to update game hud in a ccsprite or ccnodeclass?
Main Scene;
-(id) init
{
if ((self = [super init]))
{
gameHud = [GameHUD gamehud];
[self addChild:gameHud z:2 tag:99];
}
}
My GameHud
+(id) gamehud
{
return [[self alloc] init];
}
-(id) init
{
if ((self = [super init]))
{
//bunch of labels
}
}
-(void)showName: :(Object *)obj
{
NSLog(#"Object name is %#", obj.name);
[_labelSpeed setString:obj.name];
}
In Object Class:CCSprite
-(void) onTouch
{
//obj is the object with name property that I want to use
GameHUD *gamehud= (GameHUD *)[self.parent getChildByTag:99]; // does not send the obj to gamehud and showName is not called
//GameHud *gamehud= [GameHud alloc] init]; // this displays nslog but doesnt update _label
[gamehud showName:obj];
}
First of all use a singlton or you will create a new GameHub everytime you call +(id) gamehud. i think this could be your problem: you add one GameHUD to the scene and call showName: of another object of GameHUD. Another problem is your -(id)init - you dont return self! so you never get your GameHUD
static GameHUD *sharedInstance = nil;
+(id) gamehud {
if( !sharedInstance ) {
sharedInstance = [[GameHUD alloc] init]
}
return sharedInstance;
}
-(id) init {
self = [super init];
if ( self ) {
//bunch of labels
sharedInstance = self;
}
return self; //i dont see this in your code!
}
from now you can access your hud from every point you want and you dont need to handle with tags. Be careful, its not the best way to create a Singleton (ask google). Dont call ..alloc] init] use only [GameHUD gamehud];
-(void) onTouch {
[[GameHUD gamehud] showName:obj];
}
Good Luck!
You may need to create a singleton or something like a semi singleton. Just add new nsobject class name "SingletonGameHud" to your app
SingletonGameHud.h
#import <Foundation/Foundation.h>
#import "GameHUD.h"
//create singleton class to use gamehud in movingobject class
#interface SingletonGameHud : NSObject
{
GameHUD *gamingHud;
}
#property(nonatomic,strong) GameHUD *gamingHud;
+(SingletonGameHud *)sharedInstance;
#end
SingletonGameHud.m
#import "SingletonGameHud.h"
#import "GameHUD.h"
#implementation SingletonGameHud
#synthesize gamingHud=_gamingHud;
+ (SingletonGameHud *)sharedInstance
{
static SingletonGameHud *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[SingletonGameHud alloc] init];
// Do any other initialisation stuff here
});
return sharedInstance;
}
- (id)init {
if (self = [super init]) {
_gamingHud = [GameHUD hud];
}
return self;
}
#end
in your game scene call
SingletonGameHud *sharedInstance= [SingletonGameHud sharedInstance];
hud = sharedInstance.gamingHud;
[self addChild:hud z:2 tag:99];
in your on touch method call
-(void) onTouch
{
SingletonGameHud *sharedInstance= [SingletonGameHud sharedInstance];
[sharedInstance.gamingHud showName:obj];
}
init method is declared in NSObject class hence, the client code can create a new instance of my singleton class, is there any way to achieve the real singleton such that client cannot create a new instance.
Just do this:
static SingletonClass *singleton;
+ (SingletonClass *)sharedInstance
{
#synchronized(self) { //For thread safety
if (singleton == nil) {
[[self alloc] init];
}
return singleton;
}
}
-(id)init
{
if (singleton) { //This way init will always return the same instance
return singleton;
}
self = [super init];
if (self) {
singleton = self;
}
return singleton;
}
This is a proper way to do a singleton in objective c
+ (id)sharedManager
{
static dispatch_once_t onceQueue;
static SingletonObjectClass *singleton = nil;
dispatch_once(&onceQueue, ^{
singleton = [[self alloc] init];
});
return singleton;
}
- (id)init {
self = [super init];
if (self) {
//.....
}
return self;
}
init method is for initialization of instance variables. on its own will not create the object. Alloc, copy methods needs to be overridden to achieve a real single ton.
Hope this should clarify.
+ (id)alloc {
NSLog(#"%#: use +sharedInstance instead of +alloc", [[self class] name]);
return nil;
}
+ (id)new {
return [self alloc];
}
+ (SingletonClass *)sharedInstance {
static SingletonClass *myInstance = nil;
if (!myInstance)
{
myInstance = [[super alloc] init];
}
return myInstance;
}
You can return a static object of the class each time, making it a singleton.
#implementation Singleton
#synthesize testVar;
+ (Singleton*) sharedObject {
static Singleton * myInstance = nil;
if (myInstance == nil) {
myInstance = [[[self class] alloc] init];
testVar = 5;
// Set default values if needed
return myInstance;
}
To access object and its members:
[[Singleton sharedObject] testVar]
I created a Singleton class named DataManager. I've set up some caching. However, when attempting to call the cache instance methods from within another instance method of DataManager, I'm getting EXC_BAD_ACCESS error on the line:
NSMutableArray *stops = [[DataManager sharedInstance] getCacheForKey:#"stops"];
DataManager.h
#interface DataManager : NSObject {
FMDatabase *db;
NSMutableDictionary *cache;
}
+ (DataManager *)sharedInstance;
// ... more methods
- (id)getCacheForKey:(NSString *)key;
- (void)setCacheForKey:(NSString *)key withValue:(id)value;
- (void)clearCache;
DataManager.m
- (NSArray *)getStops:(NSInteger)archived {
NSMutableArray *stops = [[DataManager sharedInstance] getCacheForKey:#"stops"];
if (stops != nil) {
NSLog(#"Stops: %#", stops);
return stops;
}
stops = [NSMutableArray array];
// set stops...
[[DataManager sharedInstance] setCacheForKey:#"stops" withValue:stops];
return stops;
}
It seems to occur when called from another view controller. That is the first view controller no error, second view controller, error.
This is my first attempt at a Singleton, so I'm sure I am making a simple mistake. But I am failing to see it myself.
Note: I've tried [self getCache...] with the same result.
UPDATE
Here is my Singleton implementation. Adapted from http://www.galloway.me.uk/tutorials/singleton-classes/
+ (DataManager *)sharedInstance {
#synchronized(self) {
if (!instance) {
instance = [[super allocWithZone:NULL] init];
}
}
return instance;
}
+ (id)allocWithZone:(NSZone *)zone {
return [[self sharedInstance] 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]) {
if (db == nil){
BourbonAppDelegate *appDelegate = (BourbonAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate createEditableCopyOfDatabaseIfNeeded];
db = [[FMDatabase alloc] initWithPath:[appDelegate getDBPath]];
}
if (![db open]) {
NSAssert(0, #"Failed to open database.");
[db release];
return nil;
}
[db setTraceExecution:YES];
[db setLogsErrors:TRUE];
cache = [NSMutableDictionary dictionary];
NSLog(#"cache: %#", cache);
}
return self;
}
Your cache object is autoreleased, so it's no longer in memory when you try to access it.
Use [NSMutableDictionary alloc] init] instead of [NSMutableDictionary dictionary] to get an instance that is retained.
Not a direct answer to your question, which was already answered.
However I'd just like to point out that your singleton implementation is sub-optimal. #synchronized is very expensive, and you can avoid using it every time you access the singleton:
if (!instance) {
#synchronized(self) {
if (!instance) {
instance = [[super allocWithZone:NULL] init];
}
}
}
An even better way to initialize a singleton would be:
+ (DataManager *)sharedInstance {
static DataManager *instance;
static dispatch_once_t donce;
dispatch_once(&donce, ^{
instance = [[self alloc] init];
});
return instance;
}
I have been reading about an objective-c singleton example from http://getsetgames.com/2009/08/30/the-objective-c-singleton/.
The .m code looks like
+(MySingleton*)sharedMySingleton{
#synchronized([MySingleton class])
{if (!_sharedMySingleton)
if(!_sharedMySingleton)
return _shareMySingleton;
}
....
-(id)init{
self = [super init];
if(self != nil){}
return self;
}
....
Thanks for your example, but I have a confused place, in your code, I am wondering in which place the static MySingleton* _sharedMySingleton is initialized. for example if we would have to have some implementation like
-(id)init{
self = [super init];
if(self != nil){
_sharedMySingleton = self
}
return self;
}
You miscopied a part of the code from the link you posted by mistake.
#implementation MySingleton
static MySingleton* _sharedMySingleton = nil;
+(MySingleton*)sharedMySingleton
{
#synchronized([MySingleton class])
{
if (!_sharedMySingleton)
[[self alloc] init];
return _sharedMySingleton;
}
return nil;
}
+(id)alloc
{
#synchronized([MySingleton class])
{
NSAssert(_sharedMySingleton == nil, #"Attempted to allocate a second instance of a singleton.");
_sharedMySingleton = [super alloc];
return _sharedMySingleton;
}
return nil;
}
-(id)init {
self = [super init];
if (self != nil) {
// initialize stuff here
}
return self;
}
-(void)sayHello {
NSLog(#"Hello World!");
}
#end
looking at the code from the post you are asking about it actually makes sense.
What he is doing in the static method +(MySingleton*)sharedMySingleton is that he is checking if the _sharedMySingletonobject has a value he is returning it, if not it gets initialized.
The alloc method is the one setting the singleton object, its not being set in the initializer. technically its the same, since its going to be point on the same object that will be initialized a moment after.
I hope that clarifies your confusion.
you can use macro from http://code.google.com/p/google-toolbox-for-mac/source/browse/trunk/Foundation/GTMObjectSingleton.h it is vvveeerryyy easy to use
in implementation file (m)
GTMOBJECT_SINGLETON_BOILERPLATE(ClassName, sharedInstance)
and header file
+ (ClassName *) sharedInstance;
I have a a singleton class here is the code
#import <Foundation/Foundation.h>
#import "CustomColor.h"
#interface Properties : NSObject {
UIColor *bgColor;
CustomColor *bggColor;
}
#property(retain) UIColor *bgColor;
#property (retain) CustomColor *bggColor;
+ (id)sharedProperties;
#end
#import "Properties.h"
static Properties *sharedMyProperties = nil;
#implementation Properties
#synthesize bgColor;
#synthesize bggColor;
#pragma mark Singleton Methods
+ (id)sharedProperties
{
#synchronized(self)
{
if(sharedMyProperties == nil)
[[self alloc] init];
}
return sharedMyProperties;
}
+ (id)allocWithZone:(NSZone *)zone
{
#synchronized(self)
{
if(sharedMyProperties == nil)
{
sharedMyProperties = [super allocWithZone:zone];
return sharedMyProperties;
}
}
return nil;
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
- (id)retain {
return self;
}
- (unsigned)retainCount {
return UINT_MAX; //denotes an object that cannot be released
}
- (void)release {
// never release
}
- (id)autorelease {
return self;
}
- (id)init {
if (self = [super init])
{
bgColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:1.0];
FSColor *bc = [[FSColor alloc] init];
bc.red = bc.green = bc.blue = bc.hue = bc.sat = bc.bri = 0;
bggColor = bc;
}
return self;
}
- (void)dealloc
{
// Should never be called, but just here for clarity really.
[bgColor release];
[bggColor release];
[super dealloc];
}
#end
I have a UIView' subclass. in which i am using it. I am calling drawRect method after each second. It only run once and then app crashes.
- (void)drawRect:(CGRect)rect
{
Properties *sharedProprties = [Properties sharedProperties];
…...
….
CGContextSetFillColorWithColor(context, [[sharedProprties bgColor] CGColor]);
…..
}
What if you do self.bgColor = [UIColor colorWithRed:...]?
Without the self. I think you may be accessing the ivar directly, and therefore assigning it an autoreleased object which won't live very long (rather than using the synthesized property setter, which would retain it). I could be wrong about this, I'm stuck targeting older Mac OS X systems so I haven't been able to play much with Objective-C 2.0.
Your static sharedProperties gets never assigned. It is missing in the init method or in the sharedProperties static method.
Here's a sample pattern for singletons (last post)
Also accessing properties without self. may cause bad access errors too.
Regards
Not an answer, but note that a simple call to [Properties alloc] will mean it's no longer a singleton!
+ (id)sharedProperties
{
#synchronized(self)
{
if(sharedMyProperties == nil)
{
sharedMyProperties = [[self alloc] init];
}
}
return sharedMyProperties;
}