Apple Singleton example query? - iphone

I am a little confused by this snippet of code (presented in the CocoaFundamentals guide) that overrides some of the methods when creating a singleton instance.
static id sharedReactor = nil;
+(id)sharedInstance {
if(sharedReactor == nil) sharedReactor = [[super allocWithZone:NULL] init];
return sharedReactor;
}
.
+(id)allocWithZone:(NSZone *)zone {
return[[self sharedInstance] retain];
}
-(id)retain {
return self;
}
In the code where the singleton instance is created the +sharedInstance method calls [super allocWithZone:NILL] from the superclass (which in my case is NSObject) The allocWithZone above is only called if you attempt to use it to create a new singleton.
The bit I am confused about is the use of retain, especially seeing as retain is also overridden to return self. Can anyone explain this, could it not be written:
+(id)allocWithZone:(NSZone *)zone {
return [self sharedInstance];
}
-(id)retain {
return self;
}
EDIT_001:
Based on comments and reading various posts on the web I have decided to go with the following (see below) I have chosen to go for a shared singleton approach where if needed I would have the option of creating a second or third instance. Also at this stage as I am only using the singleton for the model portion of MVC for a simple iPhone app I have decided to leave thread safety out. I am aware its important and as I get more familiar with iPhone programming I will likely use +initialize instead (keeping in mind the subclass issue where it can be called twice) Also I have added a dealloc, firstly to log a message should the singleton be released, but also to clean things up properly should the singleton be no longer required.
#interface SharedManager : NSObject
+(id)sharedInstance;
#end
#implementation SharedManager
static id myInstance = nil;
+(id)sharedInstance {
if(myInstance == nil) {
myInstance = [[self alloc] init];
}
return myInstance;
}
-(void)dealloc {
NSLog(#"_deal: %#", [self class]);
[super dealloc];
myInstance = nil;
}
#end
In testing I found that I had a set the static variable to nil in the dealloc or it maintained its pointer to the original object. I was initially a little confused by this as I was expecting the scope of the static to be the instance, I guess its the class instead, which makes sense.
cheers gary

First, don't use this code. There is almost never a reason to do all this for a simple singleton. Apple is demonstrating a "Forced Singleton," in that it is impossible to create two of them. It is very rare to really need this. You can almost always use the "shared singleton" approach used by most of the Cocoa objects that have a singleton constructor.
Here's my preferred way of implementing shared singleton:
+ (MYManager *)sharedManager
{
static MYManager *sharedManager = nil;
if (sharedManager == nil)
{
sharedManager = [[self alloc] init];
}
return sharedManager;
}
That's it. No other code is required. Callers who use +sharedManager will get the shared instance. Callers who call +alloc can create unique instances if they really want to. This is how such famous "singletons" as NSNotificationCenter work. If you really want your own private notification center, there is no reason the class should forbid it. This approach has the following advantages:
Less code.
More flexible in cases where a non-shared instance is useful.
Most importantly: the code does what it says it does. A caller who thinks he's making a unique instance with +alloc doesn't encounter surprising "spooky action at a distance" behavior that requires him to know an internal implementation detail of the object.
If you really need a forced singleton because the object in question maps to a unique resource that cannot be shared (and it's really rare to encounter such a situation), then you still shouldn't use +alloc trickery to enforce it. This just masks a programming error of trying to create a new instance. Instead, you should catch the programming error this way:
+ (MYManager *)sharedManager
{
static MYManager *sharedManager = nil;
if (sharedManager == nil)
{
sharedManager = [[self alloc] initSharedManager];
}
return sharedManager;
}
- (id)init
{
NSAssert(NO, #"Attempting to instantiate new instance. Use +sharedManager.");
return nil;
}
// Private method. Obviously don't put this in your .h
- (id)initSharedManager
{
self = [super init];
....
return self;
}

There is a good example of different singleton methods with comments here on SO:
What does your Objective-C singleton look like?
If it helps, the example has a different approach to allocWithZone: which returns nil.

Related

Obj-C: Passing pointers to initialized classes in other classes

I initialized a class in my singleton called DataModel. Now, from my UIViewController, when I click a button, I have a method that is trying to access that class so that I may add an object to one of its dictionaries. My get/set method passes back the pointer to the class from my singleton, but when I am back in my UIViewController, the class passed back doesn't respond to methods. It's like it's just not there. I think it has something to do with the difference in passing pointers around classes or something. I even tried using the copy method to throw a copy back, but no luck.
UIViewController:
ApplicationSingleton *applicationSingleton = [[ApplicationSingleton alloc] init];
DataModel *dataModel = [applicationSingleton getDataModel];
[dataModel retrieveDataCategory:dataCategory];
Singleton:
ApplicationSingleton *m_instance;
DataModel *m_dataModel;
- (id) init {
NSLog(#"ApplicationSingleton.m initialized.");
self = [super init];
if(self != nil) {
if(m_instance != nil) {
return m_instance;
}
NSLog(#"Initializing the application singleton.");
m_instance = self;
m_dataModel = [[DataModel alloc] init];
}
NSLog(#"ApplicationSingleton init method returning.");
return m_instance;
}
-(DataModel *)getDataModel {
DataModel *dataModel_COPY = [m_dataModel copy];
return dataModel_COPY;
}
For the getDataModel method, I also tried this:
-(DataModel *)getDataModel {
return m_dataModel;
}
In my DataModel retrieveDataCategory method, I couldn't get anything to work. I even just tried putting a NSLog in there but it never would come onto the console.
Any ideas?
Most likely you are sending messages that get ignored, e.g. they're being sent to objects which don't exist/aren't the one you're looking for, and for some reason aren't crashing. This occurs in the case of messaging nil, or possibly other illegitimate values. Although you seem to expect that the m_ variables will be initialized to 0, this is not good form, and furthermore you are not following a very typical objc pattern for your singletons -- m_dataModel should be an ivar of m_instance, and m_instance should probably be declared static, as you probably don't want it accessed from other files directly. In addition, the most likely source of your bug is somehow the -init method, which should never be called on a singleton -- instead do something like this:
+ (ApplicationSingleton *)sharedInstance {
static ApplicationSingleton *instance = nil;
if(!instance) {
instance = [[self alloc] init]; //or whatever custom initializer you would like, furthermore some people just put the initialization code here and leave -init empty
}
return instance;
}
the code you have now leaks because you allocate an object (self) and don't release it before returning a potentially different instance (the shared one if one already exists), such that the newly allocated one is typically lost.

Correct way to alloc shared instance (singleton)?

I am looking at singletons and I was curious about the correct way to do the alloc, from looking at the docs, books & web there seems to be a few few methods in use.
M1:
static ReactorClass *sharedReactor = nil;
+(ReactorClass *)sharedInstance {
if(sharedReactor == nil) {
sharedReactor == [[ReactorClass alloc] init];
}
return sharedReactor;
}
M2:
static ReactorClass *sharedReactor = nil;
+(ReactorClass *)sharedInstance {
if(sharedReactor == nil) {
sharedReactor == [[super allocWithZone:NULL] init];
}
return sharedReactor;
}
M3:
static ReactorClass *sharedReactor = nil;
+(ReactorClass *)sharedInstance {
if(sharedReactor == nil) {
sharedReactor == [[[self class] alloc] init];
}
return sharedReactor;
}
many thanks ...
gary
I tend to write them like this:
+ (id)sharedFoo
{
static Foo *_sharedFoo;
if (_sharedFoo == nil)
{
_sharedFoo = [[self alloc] init];
}
return _sharedFoo;
}
but, be aware that the above code is not thread-safe. If you need a thread-safe implementation, Chris Hanson has a good suggestion, which is to create the instance in an overridden implementation of +initialize.
Using [self class] is really a waste in this case - M1 and M3 aren't really that different unless you have subclasses involved, and the reality is that the rest of the implementation isn't up to it.
Consider what happens if you create a subclass of ReactorClass like this:
#interface MyReactorClass : ReactorClass {}
#end
#implementation MyReactorClass
#end
If you call [MyReactorClass sharedInstance] you can see that its reading from a single static variable sharedReactor. Thats ok if you only create one subclass but you need to be very conscious of that, and the fact that any 3rd party libraries you call don't also use the same base class for the singletons they create but you don't know about. If, as Mark suggested, you copy the M3 code into your subclass, it will work better but you need to ask yourself "why did I subclass this?" - you got little benefit and would have been better off coding it completely, instead of relying on the implementation details of the superclass.
To do it properly, you'd keep a static dictionary (create during the +initialise of the base class), and insert entries into it keyed by the actual class of the singleton you were creating.
Worrying about whether to override alloc or allocWithZone: is again a subclassing thing but really, anyone who inherits from a singleton superclass and then screws around with its allocation methods deserves the bad behaviour they get. If you want to code the perfect singleton base class, you should create and DOCUMENT additional methods that get called so that subclassers can solve any problem they might think of without messing with your infrastructure.
Personally, my singletons throw exceptions out of all methods starting with init and do their real initialisation in an unknown method (ok, its called _init) - that GUARANTEES that people misusing the singleton class don't get unexpected behaviour.
It really boils down to "how much do you trust your subclasser". If you assume he's an idiot, you need to override things like release, retain, etc. If you assume he follows the memory management rules, you can leave those things alone because they'll just work. Apple are really a bit stupid in this regard in their sample code; they are somewhat paranoid but nowhere near idiot-proof.
If you put M3 in the implementation of ReactorClass then it is the same as M1 allocating and returning a ReactorClass. However M3 can if put in the implementation of a subclass of ReactorClass then will return a pointer to an object of that subclass.
M2 always returns the superclass of the implementation it is in.

How should I handle a failure in an init: method in Objective-C?

Let's say I'm building a new class for the iPhone in Objective-C. In one of my init methods I want to manually allocate some memory. So, I might have something like this:
- (id)initWithSomeObject:(SomeObject *)someObject {
self = [super init];
if (self != nil) {
myObject = someObject;
[myObject retain];
if ( (memory = calloc(1, sizeof(SomeStruct)) == NULL) {
// What should I do here to clean up
[self release];
self = nil;
}
}
return self;
}
Now, assuming that the calloc() could fail, and that failing to allocate memory is catastrophic for my object, what should I do inside the if-body to clean up properly? Is there an Objective-C idiom or pattern that I should be using?
Edit: I included the code posted by Rob Napier. But, I still have to release myObject, right? Or does the added code somehow trigger dealloc()?
Yes, you should release yourself and then return nil.
[self release];
self = nil;
See Issues with Initializers in the Concepts in Objective-C Programming guide.
You need to clean up anything you need to and then set the self reference to nil. Apple Dev Portal has an article:
Link
I just tried. -dealloc gets called due to [self release], so myObject would not need to get released in initWithSomeObject. To be sure, you might move myObject = [someObject retain]; (I prefer that style in case -retain might fail for some reason) below the call that might fail (if that's possible).

Unexpected Singleton class behavior on iPhone, am I doing something wrong?

I'm implementing a singleton class as follows:
static Singleton* _singletonInstance;
#implementation Singleton
+(void)initialize
{
_singletonInstance = [[Singleton alloc] init];
}
+(Singleton*)instance
{
return(_singletonInstance);
}
initialize only gets called the first time someone calls instance. I then have a method that I can call to set up some instance variables. So it ends up looking like this.
_singleton = [Singleton instance];
[_singleton setupWithParams: blah];
When i get an instance of this singleton inside an object, it works fine the first time; However, after i dealloc and create a new copy of the object that needs an instance of the singleton, i get a BAD ACCESS error when I try to call the setup function.
Just to test things I print out the address of the instance before I make the setup call and both times they report the same address, but when i check the error log for BAD ACCESS call, it lists a completely different memory address.
Does anyone have any ideas why this pointer to the instance seems to look fine when I print it, but when I make a call to it, it is seemingly pointing to random data?
The pointer value looks valid because it used to be, but most likely the memory has been free'd, which is why what it points to looks like random data.
You've acquired one reference with your [[Singleton alloc] init] above, but is there a release somewhere else that might be executing? I bet your code is calling instance, and then release-ing later, even though your code never acquired a reference. And that shouldn't be necessary for a singleton anyways. Just a guess...
Are you deallocing your _singletonInstance somewhere?
I'm using much more complex, but very stable version of Singleton template (taken with description from Brandon "Quazie" Kwaselow Blog):
static SampleSingleton *sharedSampleSingletonDelegate = nil;
+ (SampleSingleton *)sharedInstance {
#synchronized(self) {
if (sharedSampleSingletonDelegate == nil) {
[[self alloc] init]; // assignment not done here
}
}
return sharedSampleSingletonDelegate;
}
+ (id)allocWithZone:(NSZone *)zone {
#synchronized(self) {
if (sharedSampleSingletonDelegate == nil) {
sharedSampleSingletonDelegate = [super allocWithZone:zone];
// assignment and return on first allocation
return sharedSampleSingletonDelegate;
}
}
// on subsequent allocation attempts return nil
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 {
//do nothing
}
- (id)autorelease {
return self;
}
Valerii's code is better for implementing a singleton, but the problem is almost certainly that the code that calls [Singleton instance] is operating as if it has ownership without actually taking ownership using retain, and then is later releasing it.
Look there for your bug, and read the Memory Managment Rules.
Also, in Xcode, enable NSZombieEnabled and the console will show you when you try to message the object after its been released.

Objective-C/iPhone Memory Management Static Variables

I have a static method that creates an instance of the class and puts it in the static variable. I am wondering what the proper way of memory management is in this situation.
You can't put it in the dealloc-method, because although it can access the static variable any instance method that is created that get's released will also release the sharedInstance.
I guess there might be an option of creating a static destroy method which will manualy release the memory and can be called by the user from appWillTerminate, but that seems a bit odd.
So, again, the question:
What is the proper way of releasing a static variable?
// MyClass.m
#import "MyClass.h"
static MyClass *myClass; // How to properly do memory management
#implementation MyClass
+ (MyClass *)sharedMyClass {
if (myClass == nil) myClass = [[MyClass alloc] init];
return myClass;
}
#end
You can either not release them, which is fine since the app is shutting down anyway. Cocoa on the iPhone already does this, it doesn't completely delete everything, it just lets the app get blown away.
Or you can delete it from appWillTerminate or some other shutdown function.
You'll want to have a look at "Creating a Singleton" on the iPhone dev center to see how to properly implement that pattern. You won't be releasing your singleton, just letting it die when the application exits.
Also, if you're multithreaded you'll probably want to wrap that alloc in a #synchronize( self ) {}
Here is the full text:
Some classes of Foundation and the
Application Kit create singleton
objects. In a “strict” implementation,
a singleton is the sole allowable
instance of a class in the current
process. But you can also have a more
flexible singleton implementation in
which a factory method always returns
the same instance, but you can
allocate and initialize additional
instances.The NSFileManager class fits
this latter pattern, whereas the
UIApplication fits the former. When
you ask for an instance of
UIApplication, it passes you a
reference to the sole instance,
allocating and initializing it if it
doesn’t yet exist.
A singleton object acts as a kind of
control center, directing or
coordinating the services of the
class. Your class should generate a
singleton instance rather than
multiple instances when there is
conceptually only one instance (as
with, for example, NSWorkspace). You
use singleton instances rather than
factory methods or functions when it
is conceivable that there might be
multiple instances one day.
To create a singleton as the sole
allowable instance of a class in the
current process, you need to have an
implementation similar to Listing
2-15. This code does the following:
Declare a static instance of your
singleton object and initialize it to
nil. In your class factory method for
the class (named something like
“sharedInstance” or “sharedManager”),
generate an instance of the class but
only if the static instance is nil.
Override the allocWithZone: method to
ensure that another instance is not
allocated if someone tries to allocate
and initialize an instance of your
class directly instead of using the
class factory method. Instead, just
return the shared object. Implement
the base protocol methods
copyWithZone:, release, retain,
retainCount, and autorelease to do the
appropriate things to ensure singleton
status. (The last four of these
methods apply to memory-managed code,
not to garbage-collected code.)
Listing 2-15 Strict implementation of
a singleton static MyGizmoClass
*sharedGizmoManager = nil;
+ (MyGizmoClass*)sharedManager {
if (sharedGizmoManager == nil) {
sharedGizmoManager = [[super allocWithZone:NULL] init];
}
return sharedGizmoManager; }
+ (id)allocWithZone:(NSZone *)zone {
return [[self sharedManager] 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; }
If you want a singleton instance (created and
controlled by the class factory
method) but also have the ability to
create other instances as needed
through allocation and initialization,
do not override allocWithZone: and the
other methods following it as shown in
Listing 2-15.
UPDATE: There is now a much easier way to create a singleton
+ (MyClass*)sharedInstance
{
static MyClass* _sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedInstance = [[MyClass alloc] init];
});
return _sharedInstance;
}
Using this new style you don't need to worry about the #syncronize or overriding the memory management methods.
static variable or class remains in memory Untill lifetime of your application
So if it is UnUsed then make
Your_variable = nil;
while declaring use static _datatype variable = nil;
which help while initializing .. and memory management
///**************************
// MyClass.m
#import "MyClass.h"
static MyClass *myClass = nil;
#implementation MyClass
+ (MyClass *)sharedMyClass {
if (myClass == nil)
myClass = [[MyClass alloc] init];
return myClass;
}
#end