Multiple init calls to a singleton


#1

The sharedStore singleton allows for multiple init calls via [[BNRItemStore alloc]init].

After an object has been allocated and then initialized, are subsequent initializations ignored?

Can I assume the init portion of the calls below are ignored?
id *anObject=[BNRItemStore sharedStore]init];
id *anotherObject=[BNRItemStore sharedStore]init];

It appears that the instance variables are not nilled. Can I count on this?


#2

There is nothing special about init methods. They put objects in their initial, squeaky clean states after the allocation. If you call an init method again it will go an do its job, but this is something you should not do. You should call an init method only once, especially if you don’t know how the super class will react to an init method invocation after it has already been initialised.

If you want a squeaky clean object, create a new one; don’t init an existing object again.

//  main.m

#import <Foundation/Foundation.h>

#define MY_Log() NSLog (@"%s: %@...", __PRETTY_FUNCTION__, [self class])

@interface Foo : NSObject
@end

@interface FooBar : Foo
@end

int main (int argc, const char * argv[])
{
    @autoreleasepool {
        // alloc and init separately
        FooBar *fooBar = [FooBar alloc];
        fooBar = [fooBar init];
        
        // Call init again
        fooBar = [fooBar init];
        fooBar = [fooBar init];        
    }
    fflush (NULL);
    return 0;
}

@implementation Foo

- (id)init
{
    if (self = [super init])
    {
        MY_Log ();
    }
    return self;
}

@end

@implementation FooBar

- (id)init
{
    if (self = [super init])
    {
        MY_Log ();
    }
    return self;
}

@end

Its output:

2012-09-04 17:07:48.324 Init2x[24580:403] -[Foo init]: FooBar...
2012-09-04 17:07:48.326 Init2x[24580:403] -[FooBar init]: FooBar...
2012-09-04 17:07:48.326 Init2x[24580:403] -[Foo init]: FooBar...
2012-09-04 17:07:48.327 Init2x[24580:403] -[FooBar init]: FooBar...
2012-09-04 17:07:48.327 Init2x[24580:403] -[Foo init]: FooBar...
2012-09-04 17:07:48.328 Init2x[24580:403] -[FooBar init]: FooBar...

#3

So would you suggest that additional code is needed in the BNRItemStore?

It seems like we have trapped the alloc portion of [[BNRItemStore alloc]init], but not the init portion.

A user could frequently call BNRItemStore *aStore=[[BNRItemStore alloc]init], which would be calling multiple inits to the same object.


#4

[quote=“r4eemesa”]So would you suggest that additional code is needed in the BNRItemStore?

It seems like we have trapped the alloc portion of [[BNRItemStore alloc]init], but not the init portion.

A user could frequently call BNRItemStore *aStore=[[BNRItemStore alloc]init], which [color=#FF0000]would be calling multiple inits to the same object[/color].[/quote]
[[BNRItemStore alloc]init] creates and initialises a new object, each time it is invoked.


#5

I’m getting a bit confused, so let me start over.

My question is in reference to the creation of a Singleton using the design pattern outlined in the BNR iOS book, Chapter 9. This is the same design pattern that Apple recommends here:
developer.apple.com/library/mac … jects.html

My question is simple… Do multiple init calls to an object present a problem. If so, does that suggest additional code is needed in the Chapter 9 example to prevent such?

For example:

If [BNRItemStore sharedStore] is called, all is happy. A singleton is created.
If BNRItemStore *myObject=[[BNRItemStore alloc]init] is called, the allocWithZone class method is called, referencing back to the sharedStore method. So in this case, init is called twice if a new object is created. If the object already exists, init is sent once to the new object via the original call.

In all cases, using [[BNRItemStore alloc]init], init is sent to an existing allocated and initialized object.

The allocWithZone method in the BNRItemStore class insures only one allocation. But, there is nothing that prevents multiple init calls.

There are two previous threads that asked this same question but I could not find a satisfying answer.

Sorry if I am overlooking the obvious.


#6

This seems better:

#import “RLSharedSource.h”

static RLSharedSource *theSource=nil;

@implementation RLSharedSource

  • (RLSharedSource *)sharedSource{

    if (!theSource){
    theSource=[[super allocWithZone:nil]init];
    }
    return theSource;
    }

  • (id)allocWithZone:(NSZone *)zone{

    NSAssert((theSource==nil), @“Attempted to allocate and init a singleton”);

    theSource=[super allocWithZone:nil]; //no init in this statement
    return theSource;
    }


#7

[quote=“ibex10”][quote=“r4eemesa”]
[[BNRItemStore alloc]init] creates and initialises a new object, each time it is invoked.[/quote][/quote]

please correct me if i’m wrong, but why is that?
since the second time when alloc is called, it just called the method sharedStore, which returns the static sharedStore object.

so [[BNRItemStore alloc]init] will always returns the same reference, it’s just every time when init is called it will do its job.


#8

My concern is the potential for multiple calls to “init”