1

*I definitely need a break... cause was simple - array was not allocated... Thanks for help. Because of that embarrassing mistake, I flagged my post in order to delete it. I do not find it useful for Users ;) *

I have just tried to create a singleton class in iOS, but I probably I am making a mistake. Code (no ARC is a requirement):

#import "PeopleDatabase.h"
#import "Person.h"

#import <Foundation/Foundation.h>

@interface PeopleDatabase : NSObject{objetive
    NSMutableArray* _arrayOfPeople;
}

+(PeopleDatabase *) getInstance;

@property (nonatomic, retain) NSMutableArray* arrayOfPeople;


@end

--

    @implementation PeopleDatabase
    @synthesize arrayOfPeople = _arrayOfPeople;

    static PeopleDatabase* instance = nil;

    -(id)init{
        if(self = [super init]) {
            Person* person = [[[Person alloc] initWithName:@"John" sname:@"Derovsky" descr:@"Some kind of description" iconName:@"johnphoto.png" title:Prof] retain];

            [_arrayOfPeople addObject:person];
            NSLog(@"array count = %d", [_arrayOfPeople count]); // <== array count = 0 
            [person release];
        }
        return self;
    }

    +(PeopleDatabase *)getInstance {
        @synchronized(self)
        {
            if (instance == nil)
                NSLog(@"initializing");
                instance = [[[self alloc] init] retain];
                NSLog(@"Address: %p", instance);
        }
        return(instance);
    }

    -(void)dealloc {

        [instance release];
        [super dealloc];
    }
@end

When invoking getInstance like here:

PeopleDatabase *database = [PeopleDatabase getInstance];
NSLog(@"Adress 2: %p", database);

Address 2 value the same value as in getInstance.

radekEm
  • 4,617
  • 6
  • 32
  • 45
  • What exactly do you mean by "Address 2 value the same value as in getInstance." ? – Petar Mar 13 '13 at 11:05
  • it should be the same address.. since its the same object? the object you returned in getInstance is the one database was assigned to. – Fonix Mar 13 '13 at 11:06
  • See [this answer](http://stackoverflow.com/a/145395/730701). – Adam Mar 13 '13 at 11:07
  • in this function +(PeopleDatabase *)getInstance i think you need to place curly Braces correctly : like this +(PeopleDatabase *)getInstance { @synchronized(self) { if (instance == nil) { NSLog(@"initializing"); instance = [[[self alloc] init] retain]; NSLog(@"Address: %p", instance); } } return instance; } – Neelam Verma Mar 13 '13 at 11:09
  • What is your problem? What is the full output? And where do you alloc/init _arrayOfPeople? – Hermann Klecker Mar 13 '13 at 11:10
  • @Fonix Yes. I have mentioned that to note that instance is returned properly. – radekEm Mar 13 '13 at 11:13
  • @HermannKlecker I did not alloc the array... I need a break! Thanks. – radekEm Mar 13 '13 at 11:23
  • Use the way that Apple recommends to create a Singleton. Like in my answer. – Fogmeister Mar 13 '13 at 11:32
  • @Fogmeister Thats what I will surely do. Thanks! – radekEm Mar 13 '13 at 11:35

6 Answers6

25

The standard way of creating a singleton is like...

Singleton.h

@interface MySingleton : NSObject

+ (MySingleton*)sharedInstance;

@end

Singleton.m

#import "MySingleton.h"

@implementation MySingleton

#pragma mark - singleton method

+ (MySingleton*)sharedInstance
{
    static dispatch_once_t predicate = 0;
    __strong static id sharedObject = nil;
    //static id sharedObject = nil;  //if you're not using ARC
    dispatch_once(&predicate, ^{
        sharedObject = [[self alloc] init];
        //sharedObject = [[[self alloc] init] retain]; // if you're not using ARC
    });
    return sharedObject;
}

@end
Fogmeister
  • 76,236
  • 42
  • 207
  • 306
2

Check this apple doc on how to create singleton instance:

https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html

arun.s
  • 1,528
  • 9
  • 12
2
    @synchronized(self)
    {
        if (instance == nil)
            NSLog(@"initializing");
            instance = [[[self alloc] init] retain];
            NSLog(@"Address: %p", instance);
    }

You appear to be missing your braces for that if statement. As written, the only thing you do different when instance == nil is emit a log message.

mah
  • 39,056
  • 9
  • 76
  • 93
  • Thats true of course... Terrible mistake... Thanks for that, but it is not a cause... – radekEm Mar 13 '13 at 11:22
  • That is right but does not solve the root cause. Although bad style but the oritinal statement without the nslogs would have worked fine. – Hermann Klecker Mar 13 '13 at 11:26
  • You're right that it doesn't solve the root cause, but I definitely don't see " the oritinal statement without the nslogs would have worked fine" being valid. Get past the root error, and with the missing braces, you're creating a new instance with every call to `getInstance`. This, coupled with `_arrayOfPeople` being tied to the instance, removes the notion of having a singleton. – mah Mar 13 '13 at 11:32
1

After web reading and personal practicing, my current singleton implementation is:

@interface MySingleton

@property myProperty;
+(instancetype) sharedInstance;

@end


@implementation MySingleton

+ (instancetype) sharedInstance
{
    static dispatch_once_t pred= 0;
    __strong static MySingleton *singletonObj = nil;
    dispatch_once (&pred, ^{
        singletonObj = [[super allocWithZone:NULL]init];
        singletonObj.myProperty = initialize ;
    });

    return singletonObj;
}

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

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

this is a thread safe implementation and avoids the risk to create new objects by calling "alloc init" on your class. Attributes initialization has to occur inside the block, not inside "init" override for similar reasons.

Enrico Cupellini
  • 447
  • 7
  • 14
0

in this function +(PeopleDatabase *)getInstance i think you need to place curly Braces correctly : like this

+(PeopleDatabase *)getInstance {
    @synchronized(self)
    {
        if (instance == nil)
        {
            NSLog(@"initializing");
            instance = [[[self alloc] init] retain];
            NSLog(@"Address: %p", instance);
        }
        return instance ;
    }
}
Michael Mior
  • 28,107
  • 9
  • 89
  • 113
Neelam Verma
  • 3,232
  • 1
  • 22
  • 33
0

This is an error that can be avoided by some disziplined convention which is to always use curly brackets followed by if and else.

+(PeopleDatabase *)getInstance {
    @synchronized(self)
    {
        if (instance == nil)
            NSLog(@"initializing");
            instance = [[[self alloc] init] retain];
            NSLog(@"Address: %p", instance);
    }
    return(instance);
}

If instance is nil then the very next statement and only that is executed. And that is the nslog and not the allocation. Then instance is allocated anyway, regardless wether it was used before or not. This will provide you with a new singleton on each call. BTW that causes a leak.

+(PeopleDatabase *)getInstance {
    @synchronized(self)
    {
        if (instance == nil) {
            NSLog(@"initializing");
            instance = [[[self alloc] init] retain];
            NSLog(@"Address: %p", instance);
        }
    }
    return(instance);
}

But this error came in while debugging. It may confuse you but does not solve your original problem. Please add an alloc and init and retain for _arrayOfPeople as well.

-(id)init{
    if(self = [super init]) {
        Person* person = [[[Person alloc] initWithName:@"John" sname:@"Derovsky" descr:@"Some kind of description" iconName:@"johnphoto.png" title:Prof] retain];

        _arrayOfPeople = [[[NSMutableArray alloc] init] retain]; //dont forget the release
        [_arrayOfPeople addObject:person];
        NSLog(@"array count = %d", [_arrayOfPeople count]); // <== array count = 1 !!!  
        [person release];
    }
    return self;
}

In your code _arrayOfPeople is nil and addObject is sent to nil which does not cause an abort but does not do anything either. Then count is sent to nil wich returns 0/nil.

Hermann Klecker
  • 14,039
  • 5
  • 48
  • 71