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.
Related
I have been following the iPhone development videos on iTunes U and so far so good. I think I understood things well enough.
The thing is that on the examples they provide they never create custom class methods just like those that you use on some Foundation classes (like [NSString string]) so I'm not sure as to how I should go about creating my own class method to return an autoreleased instance of my class.
I do know how to create a retained object using an instance method but I'd rather use a class method because I prefer it, I'm just not sure if this implementation would be the most appropriate to return an autoreleased object:
+ (PhotoViewController*)initWithImageView:(UIImageView*)imageView
{
PhotoViewController *toreturn = [[PhotoViewController alloc] init];
toreturn.imageview = imageView;
[toreturn autorelease];
return toreturn;
}
Thanks a lot for any help you may provide.
A class method can return either a retained or autoreleased object as you wish, and your code returns an autoreleased object perfectly appropriately.
However you should probably name your method differently. Since your method begins with init, that implies it is initialising an alloced object (and should therefore be an instance method rather than a class method). I'd suggest naming the method photoViewControllerWithImageView: if it's going to return an autoreleased object.
Also, I'd probably write it as return [toreturn autorelease]; but I guess that's a style preference of mine.
I think it's a good practice to check whether toreturn is nil or not before accessing imageview property.
I am curious if the code I am using here is a good way of doing this. Basically I am creating a simple model object (in the MVC sense) by lazy instanciating it from within my ViewController. The idea being that the first time I call [[self dataModel] doSomething]; it creates a new (or reuses an existing) object. I was specifically concerned with setting the property and correctly releasing the local alloc, any comments would be much appreciated.
// INTERFACE
DataModel *dataModel;
#property(nonatomic, retain) DataModel *dataModel;
// IMPLEMENTATION
#synthesize dataModel;
// Lazy Instanciation ...
- (DataModel *)model {
if(!dataModel) {
DataModel *tempDataModel = [[DataModel alloc] init];
[self setDataModel:tempDataModel;
[tempDataModel release];
}
return dataModel;
}
// Clean up
- (void)dealloc {
[dataModel release];
[super dealloc];
}
OR: (although I don't really like this as it looks confusing to me)
// Lazy Instanciation ...
- (DataModel *)model {
if(!dataModel) {
[self setDataModel:[[DataModel alloc] init]];
[dataModel release];
}
return dataModel;
}
gary.
The first one is better, and fairly standard and proper. The second form is general bad form. Because it's completely unclear the object you init is the same one that you release. It's always best to think like this:
instiate object
do something with object
release object
In this case "do something with object" happens to be assigning it to a different instance variable. But it really doesn't matter what you do there, the pattern holds true. It's entirely up to the setDataModel: method what happens to the object afterward.
Personally though, I prefer the autorelease for most of these cases. Simply because you have to think about it far less.
DataModel *tempDataModel = [[[DataModel alloc] init] autorelease];
[self setDataModel:tempDataModel];
So the easier pattern to remember is:
instantiate and autorelease object
do something with object
But this is a matter of taste, and many prefer the explicit release.
The first way is clearer, although the effect is the same. Note, however, that if the idea of making dataModel a property and using the accessor's retain mechanism is to keep that all in one place the direct use of the dataModel ivar is breaking that encapsulation.
Actually, there seems to be a bit of a mix-up between this model method and the dataModel property. It would be better to restructure things so that everything is in the dataModel accessor itself, avoiding this slightly awkward redirect:
- (DataModel*) dataModel
{
if ( ! dataModel )
{
// direct ivar access is legit inside the accessor itself
// (at least, I would say so -- no doubt others will disagree!)
dataModel = [[DataModel alloc] init];
}
return dataModel;
}
You might consider overriding the dataModel synthesized getter. Otherwise, it could be a bit confusing with both the dataModel getter and the model messages.
I think you could override your synthesized getter like this:
- (DataModel *)dataModel {
if(!dataModel) {
dataModel = [[DataModel alloc] init];
}
return dataModel;
}
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.
I have a class that contains a few instance methods which need to be called from another class. I know how to do that -
TimeFormatter *myTimeFormatter = [[TimeFormatter alloc] init];
[myTimeFormatter formatTime:time];
However, I don't want to have to alloc and init TimeFormatter every time I need to call one of its methods. (I need to call TimeFormatter's methods from various methods in another class).
I tried putting
TimeFormatter *myTimeFormatter = [[TimeFormatter alloc] init];
"by itself", or not in any blocks, but when I compile, I get an "initializer element is not constant" error.
Any input is greatly appreciated!
You can use the singleton pattern. You can read more about it here.
Specifically, you'd do something like:
static TimeFormatter* gSharedTimeFormatter = nil;
#implementation TimeFormatter
+ (TimeFormatter*)sharedTimeFormatter {
if (!gSharedTimeFormatter) {
#synchronized(self) {
if (!gSharedTimeFormatter) {
gSharedTimeFormatter = [[TimeFormatter alloc] init];
}
}
}
return gSharedTimeFormatter;
}
...
#end
Notice that we check if the variable is null, and if it is, we take a lock, and check again. This way, we incur the locking cost only on the allocation path, which happens only once in the program. This pattern is known as double-checked locking.
However, I don't want to have to alloc and init TimeFormatter every time I need to call one of its methods. (I need to call TimeFormatter's methods from various methods in another class).
I think it's worth clarifying some OOP terminology here.
The reason you need to alloc and init TimeFormatter is because your methods are instance methods. Because they're instance methods, you need an instance, and that's what alloc and init provide. Then you call your methods on (send messages to) the instance ([myTimeFormatter formatTimeString:…]).
The advantage of allowing instances is that you can keep state and settings in each instance, in instance variables, and make the latter into publicly-visible properties. Then you can deliberately have multiple instances, each having its own settings configured by whatever's using that instance.
If you don't need that functionality, you don't need to make these instance methods. You can make them class methods or even C functions, and then you don't need a TimeFormatter instance. With class methods, you send messages directly to the class ([TimeFormatter formatTimeString:…]).
And if you do want settings shared among all instances (and you don't have any state to keep), then you're right that you can just have one instance—a singleton.
The reason for that parenthesis is that shared state is bad, especially if two threads may use the time formatter concurrently. (For that matter, you could say that about settings, too. What if one thread wants seconds and the other doesn't? What if one wants 24-hour and the other wants 12-hour?) Better to have each thread use its own time formatter, so that they don't get tripped up by each other's state.
(BTW, if TimeFormatter is the actual name of your class: You are aware of NSDateFormatter, right? It does let you only format/parse the time.)
Here's a detail example of a sharedMethod. Credit goes here
#implementation SearchData
#synthesize searchDict;
#synthesize searchArray;
- (id)init {
if (self = [super init]) {
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *finalPath = [path stringByAppendingPathComponent:#"searches.plist"];
searchDict = [[NSDictionary alloc] initWithContentsOfFile:finalPath];
searchArray = [[searchDict allKeys] retain];
}
return self;
}
- (void)dealloc {
[searchDict release];
[searchArray release];
[super dealloc];
}
static SearchData *sharedSingleton = NULL;
+ (SearchData *)sharedSearchData {
#synchronized(self) {
if (sharedSingleton == NULL)
sharedSingleton = [[self alloc] init];
}
return(sharedSingleton);
}
#end
A very nice, and easy, way to setup a Singleton is to use Matt Gallager's SYNTHESIZE_SINGLETON_FOR_CLASS.
It sounds like you want to make TimeFormatter a singleton, where only one instance can be created. Objective-C doesn't make this super easy, but basically you can expose a static method that returns a pointer to TimeFormatter. This pointer will be allocated and initialized the first time in, and every time after that same pointer can be used. This question has some examples of creating a singleton in Objective-C.
You are trying to declare your variable outside the class? If to do it the way you want to do it you gotta declare it as static so
static TimeFormatter *myFormatter=...
From the name of the class though i dont see why you would wnat to keep one instance of your class... you can also do this with a singleton as described above, that is if you want to keep one instance of your class for the app as a whole.
When implementing an +initialize or +load method in one of your Objective-C classes, should you always start with this kind of guard?:
#implementation MyClass
+ (void)initialize {
if (self == [MyClass class]) {
...
}
}
...
#end
Seems like code in +load and +initialize usually only wants to be executed once. So this would help avoid dupe execution when subclasses load/initialize.
I guess I'm just wanting some reinforcement from some ObjC wizards that this is necessary/common practice...
What's the common wisdom on this? would you recommend always doing this?
Is your advice the same for both +load and +initialize, or is there a difference in they way they should be handled?
thanks.
The quick answer is: No.
An in-depth discussion of this matter can be found on the Apple developer mailing list.
The gist of it is that:
The runtime will actually call +initialize on super classes before it is called on subclasses.
If you do include the guard, subclasses of your class that have their own +initialize method will not trigger dependent KVO notifications.
For an example of point #2, be sure to read this post in the thread mentioned above.
Yes, you should do this in your intialize and load methods if you are initializing globals that should only be initialized once.
That said, there are a number of cases where you may avoid it...
You shouldn't wrap with this conditional if the work needs to be performed on every inheritant of every class:
For example, adding all inherited class names for each class to a set.
edited addition: or you're establishing KVO dependencies (as mentioned by eJames)
There are also situations where you just needn't bother:
If the actions you perform are idempotent (don't change values if repeated)
The class is "sealed" (has no descendants by design)
The "idempotent" part is relevant. An initializer should just be setting the initial state (which should be the same each time). In a good initializer, repetition shouldn't matter. Although I suppose that if you forget to wrap the method in the conditional when it does matter, this might be annoying.
edited addition: A different approach, that properly reflects any initialize-only-once requirements would be to test if your properties to initialize are initialized already. i.e.
id myGlobalObject = nil;
+(void)initialize
{
if (myGlobalObject == nil)
{
myGlobalObject = [[MyGlobalClass alloc] init];
}
}
YES!!!!
Because the initialize method of a class may be invoked many times. e.g. when you implement initialize in parent class, and don't implement in sub class, then you call sub class first, the initialize of parent will invoked twice.
#implementation BaseClass
+ (void)initialize
{
NSLog(#"BaseClass initialize self=%#, class=%#", self, [BaseClass class]);
}
#end
#interface SubClass : BaseClass
#end
#implementation SubClass
// don't implement the initialize method
#end
==================
now when you call SubClass first, just like
[SNSBaseSubLogic alloc]
look the debug console, output:
BaseClass initialize self=BaseClass, class=BaseClass
BaseClass initialize self=SubClass, class=BaseClass
so, you must use
+ (void)initialize
{
if (self == [BaseClass class]) {
NSLog(#"BaseClass initialize self=%#, class=%#", self, [BaseClass class]);
}
}
to ensure the method body execute once.