Subclasses of singleton not working together - iphone

I use this code to create subclasses which are individually singletons:
+(id)sharedManager {
Class class = [self class];
static SPPanelManager *sharedManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedManager = [[class alloc] init];
});
return sharedManager;
}
And then in the .h of each subclass, there's this, with the name of the class as the return value:
+(SPWeatherManager *)sharedManager;
If these are used individually, they work perfectly, and launch their class as expected. If used together however, they all take the class of the first singleton generated.
How could i change this code so that the subclasses are all their own singletons?

It seems your complicated construct did not confuse dispatch_once a bit.
As requested (that's what dispatch_once is for, after all), sharedManager is only assigned once.

You need to create multiple singletons. Change the class factory method to test for the class, and if the base class create/return one object, and if the subclass another. You need two dispatch once objects (typing this on an iPad, could do real code later). In a more general sense, you could use a mutable dictionary to hold the dispatch object and singleton, thus supporting a virtually unlimited number of subclasses, by getting the NSString name of the class and using it as the key.

Related

Class method to return autoreleased object

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.

Change classes instantiated with loadNibNamed

I am trying to change the class of objects created with a nib with the iPhone SDK.
The reason for this is; i dont know until runtime what the class is that i want the nib object to be (though they will have the same UIView based super class), and i dont want to create a different nib for every eventuality - as the .nib will be the same for each, apart from the class of one object.
I have been successful, with a couple of methods, but either have some knock on effects or am unsure of how safe the methods I have used are:
Method 1: Override alloc, on the super class and set a c variable to the class I require:
+ (id) alloc {
if (theClassIWant) {
id object = [theClassIWant allocWithZone:NSDefaultMallocZone()];
theClassIWant = nil;
return object;
}
return [BaseClass allocWithZone:NSDefaultMallocZone()];
}
this works well, and i assume is 'reasonably' safe, though if have a nib with the correct class as the class identity in the Nib, or I alloc a subclass myself (without setting 'theClassIWant') - an object of the base class is created. I also dont really like the idea of overriding alloc...
Method 2: use object_setClass(self,theClassIWant) in initWithCoder (before calling initWithCoder on the super class):
- (id) initWithCoder:(NSCoder *)aDecoder {
if (theClassIWant) {
// the framework doesn't like this:
//[self release];
//self = [theClassIWant alloc];
// whoa now!
object_setClass(self,theClassIWant);
theClassIWant = nil;
return [self initWithCoder:aDecoder];
}
if (self = [super initWithCoder:aDecoder]) {
...
this also works well, but not all the subclasses are necessarily going to be the same size as the super class, so this could be very unsafe! To combat this i tried releasing and re-allocing to the correct type within initWithCoder, but i got the following error from the framework:
"This coder requires that replaced objects be returned from initWithCoder:"
dont quite get what this means! i am replacing an object in initWithCoder...
Any comments on the validity of these methods, or suggestions of improvements or alternatives welcome!
While I'm curious to see if you can pull this off using your approach, you may want to consider using custom placeholder objects.

Initialize a class only once

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.

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

Should +initialize/+load always start with an: if (self == [MyClass class]) guard?

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.