Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

mikezang

macrumors 6502a
Original poster
May 22, 2010
939
41
Tokyo, Japan
I have two Singleton class, I am not sure which one is better, I hope that you can give some suggestion.
Code:
#import "SingletonClass.h"

@implementation SingletonClass

static SingletonClass *sharedInstance = nil;

+ (SingletonClass *)sharedInstance {
    @synchronized(self) {
        if(sharedInstance == nil) {
            [[self alloc] init];
        }
    }

    return sharedInstance;
}

+ (id)allocWithZone:(NSZone *)zone {
    @synchronized(self) {
        if (sharedInstance == nil) {
            sharedInstance = [super allocWithZone:zone];
            return sharedInstance;  
        }
    }
    return nil; 
}

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

- (id)retain {
    return self;
}

- (NSUInteger)retainCount {
    return NSUIntegerMax;  
} 

- (void)release {
}

- (id)autorelease {
    return self;
}

@end

Code:
#import "SingletonClass.h"
 
@implementation SingletonClass
 
static SingletonClass *sharedInstance = nil;
 
+ (SingletonClass *)sharedInstance {
    if (sharedInstance == nil) {
        sharedInstance = [[super allocWithZone:NULL] init];
    }
 
    return sharedInstance;
}
 
+ (id)allocWithZone:(NSZone *)zone {
    return [[self sharedInstance] retain];
}
 
- (id)copyWithZone:(NSZone *)zone {
    return self;
}
 
- (id)retain {
    return self;
}
 
- (NSUInteger)retainCount {
    return NSUIntegerMax;
}
 
- (void)release {
}
 
- (id)autorelease {
    return self;
}
 
@end
 
A few random comments on this subject:

Mr. Hanson is a nut about unit testing. Unit testers hate, with a passion, singletons. They hate singletons because they screw up unit testing royally. They will give you all kinds of reasons why singletons are bad but the bottom line is that singletons screw up unit testing. Royally.

That said, OP, all your code that you show contains a bunch of neurotic stuff intended to prevent a bunch of problems that will never occur. Hanson's post, 178, simplifies things somewhat. And if that works for you then use it.

For me I usually just make singletons that only have class methods. No instance of the singleton class ever needs to be created. None of that neurotic code that's intended to prevent alloc/init/release/kissme whatever methods from being called is needed. If you're writing a library, like Foundation, then maybe you need that stuff. If you're just writing a plain old application where you control all the code then you don't need to override release or allocWithZone or any of that junk.
 
A few random comments on this subject:

Mr. Hanson is a nut about unit testing. Unit testers hate, with a passion, singletons. They hate singletons because they screw up unit testing royally. They will give you all kinds of reasons why singletons are bad but the bottom line is that singletons screw up unit testing. Royally.

That said, OP, all your code that you show contains a bunch of neurotic stuff intended to prevent a bunch of problems that will never occur. Hanson's post, 178, simplifies things somewhat. And if that works for you then use it.

For me I usually just make singletons that only have class methods. No instance of the singleton class ever needs to be created. None of that neurotic code that's intended to prevent alloc/init/release/kissme whatever methods from being called is needed. If you're writing a library, like Foundation, then maybe you need that stuff. If you're just writing a plain old application where you control all the code then you don't need to override release or allocWithZone or any of that junk.
Well, In fact, I just want to utility library, for example, and so on...
[singletonClass isHoliday]
[singletonClass isMarketopen]
 
Exactly.

In that case chuck all that junk you had and just implement class methods. It's very simple.
 
Exactly.
In that case chuck all that junk you had and just implement class methods. It's very simple.
So this is ok?
Code:
#import "SingletonClass.h"
 
@implementation SingletonClass
 
static SingletonClass *sharedInstance = nil;
 
+ (SingletonClass *)sharedInstance {
    if (sharedInstance == nil) {
        sharedInstance = [[super allocWithZone:NULL] init];
    }
 
    return sharedInstance;
}

@end
 
Well, In fact, I just want to utility library, for example, and so on...
[singletonClass isHoliday]
[singletonClass isMarketopen]

Write them as functions. Plain ordinary C functions:
Code:
extern BOOL isHoliday(void);
extern BOOL isMarketopen(void);
What do you gain by making them class methods? If you can't answer that with a technically sound reason, then just write functions. Why make anything more complex than it absolutely needs to be?

One of the most commonly used things in Cocoa is NSLog(), and it's a function.

If functions are "bad" or "un-Cocoa-like", then someone forgot to tell Cocoa's designers:
http://developer.apple.com/mac/libr...Foundation_Functions/Reference/reference.html
 
Write them as functions. Plain ordinary C functions:
Code:
extern BOOL isHoliday(void);
extern BOOL isMarketopen(void);
What do you gain by making them class methods? If you can't answer that with a technically sound reason, then just write functions. Why make anything more complex than it absolutely needs to be?

One of the most commonly used things in Cocoa is NSLog(), and it's a function.

If functions are "bad" or "un-Cocoa-like", then someone forgot to tell Cocoa's designers:
http://developer.apple.com/mac/libr...Foundation_Functions/Reference/reference.html
Great!

I thought everything should like to use OOP:(
 
Great!

I thought everything should like to use OOP:(

Ideally, yes. Objective C is an OO language and as such you should try and follow sound object oriented principles but if you are going to eschew them then I am with chown3; you may as well use functions.

That said, one advantage using a bunch of class methods is that you get some namespacing but its unlikely to be an issue as long as you are careful (and you can always prefix your functions).

Oh, and being a "unit testing nut" is nothing to be ashamed of. To me, the nut is the person who doesn't write a automated tests for their code' whether they are unit tests or higher level acceptance tests. ;)
 
For simple functions like this they can be either C functions or class methods and there isn't much difference. If they are conceptually related then it makes sense to make them class methods. If they rely on any state then it makes sense for them to be class methods.

I don't think there are any classes like this in UIKit or foundation. But classes like UIDevice and NSFileManager are similar. If you look at UIDevice it's basically just a bunch of properties. However, you can't use the property syntax as a class method so they have to have an instance. Also, most or all the properties are conceptually related. UIDevice could be implemented as a bunch of C functions or as a bunch of class methods with little difference to the current implementation.
 
If they rely on any state then it makes sense for them to be class methods.

Surely, if they rely on state, it makes more sense from them to be instance methods on a properly designed class?

UIDevice could be implemented as a bunch of C functions or as a bunch of class methods with little difference to the current implementation.

You don't know that because you don't know what kind of state UIDevice is tracking internally. UIDevice is certainly one of the few cases where a true singleton makes sense (there is only one device, after all) but that still doesn't preclude it from being a proper object.

UIScreen on the other hand is an example of a class that naively one might implement as a singleton. There is only one screen right? But then along comes 3.2 with external display support.

Generally, I've found that Cocoa APIs don't tend to use singletons in the strictest sense of the word, but normal objects that happen to have one or more globally available instances (think [NSNotificationCenter defaultCenter], [NSUserDefaults standardUserDefaults], [UIScreen mainScreen] etc.).

I won't deny that there are occasionally times where a simple class method or global function is useful to encapsulate a small piece of common functionality but that doesn't stop me treating it as an anti-pattern; a code smell that should indicate that you are writing procedural code that could do with refactoring to a better, OO design.

Likewise, singletons are occasionally useful (although I find the shared instance pattern to be preferable as you rarely need a true singleton) but I again treat it as an anti-pattern and an indication that something might be wrong with my application design. This is why I generally avoid singletons - not just because they are a barrier to testing as they make dependency injection harder, although that's certainly a factor - but because whilst they are occasionally the pragmatic choice, there is often a better, more cohesive and less coupled design.

Does the above matter if you're making a simple fart app that takes a few days to put together? No, but if you're writing a more complicated application that has to be maintained over a longer period of time, then I think it does.
 
OPP makes code bigger and slower. Probably burns more battery as well. It should only be used in cases where the advantages outweigh the disadvantages. That's most (non-tiny & non-fast) things, but not all.
So most of Helper and Wrapper class don't be needed, do you think so?
 
Oh, and being a "unit testing nut" is nothing to be ashamed of. To me, the nut is the person who doesn't write a automated tests for their code' whether they are unit tests or higher level acceptance tests. ;)

Except unit tests promote the thought pattern of "I have unit tests therefore I don't need to manually test as much".

Its better to make sure you rigorously test manually and run through your code with a debugger to see what is going on than it is to make sure you have unit tests for everything.

Plus if your unit tests are not kept in absolute lock step with the rest of your code you run into other problems (such as tests passing when they should fail - that will definitely ruin one of your days in the future).
 
Oh, and being a "unit testing nut" is nothing to be ashamed of. To me, the nut is the person who doesn't write a automated tests for their code' whether they are unit tests or higher level acceptance tests. ;)

The fart app that paid off the most money likely wasn't automatically unit tested. But it was among the very first to market. The 100th fart app that was finally actually properly designed and fully automatically tested probably paid off the development time at 0.5% of minimum wage. This is a tiny example, but I've seen the same happen to million dollar projects. Unless working for NASA, the FAA or FDA, a useless nut is anyone who doesn't know when dirty shortcuts are the proper trade-off for success.

For small stuff just use functions and globals (and pointers and goto's). It's far less painless to eventually rewrite the small stuff completely rather than forcing it to be reusable when you aren't.
 
The fart app that paid off the most money likely wasn't automatically unit tested. But it was among the very first to market. The 100th fart app that was finally actually properly designed and fully automatically tested probably paid off the development time at 0.5% of minimum wage. This is a tiny example, but I've seen the same happen to million dollar projects. Unless working for NASA, the FAA or FDA, a useless nut is anyone who doesn't know when dirty shortcuts are the proper trade-off for success.

For small stuff just use functions and globals (and pointers and goto's). It's far less painless to eventually rewrite the small stuff completely rather than forcing it to be reusable when you aren't.

*ahem*

me said:
Does the above matter if you're making a simple fart app that takes a few days to put together? No, but if you're writing a more complicated application that has to be maintained over a longer period of time, then I think it does.
 
Except unit tests promote the thought pattern of "I have unit tests therefore I don't need to manually test as much".

Its better to make sure you rigorously test manually and run through your code with a debugger to see what is going on than it is to make sure you have unit tests for everything.

Plus if your unit tests are not kept in absolute lock step with the rest of your code you run into other problems (such as tests passing when they should fail - that will definitely ruin one of your days in the future).

TDDis a practice that mitigates your last point.

Manual testing has value, especially with apps where the end user experience is so important but being able to repeatedly run a series of automated tests is more valuable.

Unit tests alone are not enough. You also need a good suite of high level acceptance tests.

If you are writing tests that produce false negatives, then you need to learn how to write better tests.
 
TDDis a practice that mitigates your last point.

Manual testing has value, especially with apps where the end user experience is so important but being able to repeatedly run a series of automated tests is more valuable.

Not at all.

Unit tests are only as good as the programmer who implements them. If you make a mistake in your basic assumptions, that same mistake will be replicated in your unit tests. They are not a silver bullet.

They are a tool like any other, this preaching that they are one of the saving graces of development is ridiculous. It's yet more bandwagoning of the worst kind.

I'm not arguing against unit tests in the least. I am arguing against the assumption that they are the most important part of developing stable and low bug count code.
 
I don't think I've said at any point that unit tests are some kind of silver bullet for writing bug free code and naturally, you can have 100% test coverage and still not absolutely guarantee your code is bug free. Unit tests can't help you debug memory leaks and a variety of other problems (fortunately there are plenty of other tools that can help you with these things).

My original point was about automated testing; whether they are written as part of a TDD cycle (which is equally about driving the design of your code, not just ensuring that it works) or written after the fact.

The fact is that in the majority of cases, if you can test something manually, you can or should be able to automate it. Automating it means those tests can be run repeatedly and frequently. They can be run before you check in to your version control system and they can be run as part of a continuous build process. They might not catch everything but they can and do help to catch unexpected bugs and regressions and they provide an excellent safety harness for refactoring.

I also took exception to the notion that somebody who advocates unit testing is in some way a "nut". To me, there is nothing worse than a code base with no automated tests. You can't possibly manually test everything after making a change therefore every change carries the risk of breaking something that you didn't intend to. I'd even go as far to say that on anything but the simplest of code bases, not writing automated tests is just irresponsible.

The idea that hacking your way from point A to B, taking "dirty little shortcuts" here and there, is somehow a good thing because it gets you to market quicker is often a false economy. Yes, there are absolutely times when these sacrifices need to be made but lets not kid ourselves that you are building up a technical debt in the process that will likely have to be paid off at some point in the future; the worst thing you can do is let that technical debt overwhelm your project otherwise it's your app that will be languishing behind the competition whilst they roll out new features and you are left putting out fires and fixing bugs and dealing with customer complaints. Nobody will care that you "got there first" if your customers start to abandon you.
 
I meant "nut" in a good way. Mr Hanson is a strong advocate of unit testing and just about anything I've ever read from him was on that topic.

I object to the ridiculous assertion, and I paraphrase, that no code can be good unless it's unit tested.

Gee, I thought we were talking about Singletons.
 
The first singleton class, one that makes sure createInstance is synchronized, while clever, has been shown to not work in some situations.

So neither of them is perfect. The best way is to create the object instance of the singleton right at the beginning of the program instead of when it is needed. Doing so has the added advantage of catching any error before the program goes too deep.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.