Objective C Singleton - Prevent Allocating Memeory More than Once - objective-c

I use a sinlgeton in my application for managing data that is available to the whole application, which accessed via:
static MMProductManager *sharedInstance = nil;
+(MMProductManager*)SharedInstance {
dispatch_once( &resultsToken, ^(void) {
if ( ! sharedInstance ) {
sharedInstance = [[MMProductManager alloc] init];
}
});
return sharedInstance;
}
Everything is working as expected.
In Objective C, there does not seem to be a way to hide any object's init method, and in my case having more than instance of MMProductManager would lead to data being duplicated (in the best case scenario).
What I would like to do is guard against instantiating more than one instance. Other languages seem to have this feature; i.e. marking certain methods/classes as private. I am thinking of implementing something along like:
-(id)init {
// guard against instantiating a more than one instance
if ( sharedInstance )
return sharedInstance;
if ( (self = [super init]) ) {
self->_resultsQueue = dispatch_queue_create( kMMResultQLAbel, NULL );
self->_initialized = FALSE;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(handleNotification:)
name:UIApplicationDidReceiveMemoryWarningNotification
object:0];
[self initialize];
}
return self;
}
Does this approach seem reasonable?
What would happen in the case of someone allocating this class, then calling the init described above? Would it be reasonable to override +(id)alloc? If so How would I go about doing that?
I know the convention of exposing a SharedInstance method is an implicit message to other developers to go through this method, but I would like a bit more control if possible.

You don't want to override - init (if not for some other reason) - - init is not the method that creates the instance. You want to override + alloc for this:
#implementation SingletonClass
+ (id)alloc
{
static id instance = nil;
if (instance == nil) {
instance = [super alloc];
}
return instance;
}
#end
This way you can actually prevent (almost) completely creating multiple instances of SingletonClass.
(Unless somebody falls back to calling
id trickyDifferentInstance = class_createInstance(objc_getClass("SingletonClass"), 0));
but that's very unlikely.)

Related

Factory methods in Objective-C

I make class factories like so,
#implementation Universe {
NSString *foo;
}
+ (instancetype)universeWithMeaning:(NSString *)meaning
{
return [[self alloc] initUniverseWithMeaning:meaning];
}
- (id)initUniverseWithMeaning:(NSString *)meaning
{
if (self = [super init]) {
foo = meaning;
}
return self;
}
- (void)showMeaning
{
NSLog(#"%#", foo);
}
#end
And create object like this,
Universe *universe = [Universe universeWithMeaning:#"42"];
[universe showMeaning]; // Prints 42
This works great, but the method signature of initUniverseWithMeaning: is the same as that of universeWithMeaning:, except that it's an instance method which allows it to save instance variables to the created object.
Is there a way to this without having to implement the initUniverseWithMeaning: instance method?
I know its necessary to be inside of an instance method to be able to access instance variables, so I've been experimenting with blocks. My idea was to pass a block containing instance variable assignations to the class method which would somehow execute it in the instance context.
Implementation,
#implementation Cat {
NSString *lives;
}
+ (Cat *)newCat:(void(^)(void))cat
{
cat(); // **Problem 1**
}
- (void)showLives
{
NSLog(#"%#", lives);
}
#end
Usage,
Cat *cat = [Cat newCat:^void (void) {
self.lives = 9; // **Problem 2**
}];
[cat showLives]; // I'd like this to print 9
Problem 1: How to create a Cat object and execute cat() inside it?
Problem 2: How to make self refer to the object in the block's execution environment?
Anyway, this is more of a curiosity than anything else, it's would only be practically useful to save me from writing alloc (I would just need to include a method prototype for initUniverseWithMeaning: in the .h file.)
For your problem 1 and 2, you can try this
#interface Cat ()
#property (strong) NSString *lives;
#end
#implementation Cat
+ (Cat *)newCat:(void(^)(Cat *me))cat
{
Cat *newcat = [[self alloc] init];
cat(newcat);
return newcat;
}
- (void)showLives
{
NSLog(#"%#", lives);
}
#end
Cat *cat = [Cat newCat:^(Cat *me) {
me.lives = 9;
}];
[cat showLives]; // print 9
but I can't see much use of it... Isn't this simpler?
Cat *cat = [Cat new];
cat.lives = 9;
[cat showLives];
For your real problem
Is there a way to this without having to implement the initUniverseWithMeaning: instance method?
+ (instancetype)universeWithMeaning:(NSString *)meaning
{
Universe *universe = [[self alloc] init];
if (universe) universe->foo = meaning;
return universe;
}
The first example you've posted is the correct way of creating Objective-C factory methods.
An Objective-C factory method is nothing more than a class method wrapper around an instance level init method. Generally speaking, every factory method should have a paired init method that takes the same number and type of arguments.
fooWithBar:(NSString *)bar should be paired with initWithBar:(NSString *)bar, etc.
An exception might come in when you have an init method that takes arguments, but you've create a handful of factory methods with default arguments for this method. For example:
- (instancetype)initWithString:(NSString *)string;
+ (instancetype)fooWithString:(NSString *)string {
return [[self alloc] initWithString:string];
}
+ (instancetype)fooWithBar {
return [[self alloc] initWithString:#"bar"];
}
Now, you can create the object with in the method, then modify it, and return the modified object.
For example:
+ (instancetype)fooWithString:(NSString *)string {
Foo *f = [[self alloc] init];
f.str = string;
return f;
}
But honestly, it's just better to have an initWithString: method.
Every class should have a designated initializer and every object of that class should go through the designated initializer.

Can I pass delegate as a parameter objective-c

I am working with an NSOperationQueue and I want to add new NSOperations to the NSOperationQueue. It is a queue that lives in a singleton instance of a class I have. It would make things a lot easier if I could move everything into the static class by passing the delegate.
Here is my code now as it lives in - this is in a cellForRowAtIndexPath
NSString *key = [NSString stringWithFormat:#"%#%#",cell.dataItem.ItemID, cell.dataItem.ManufacturerID];
if (![self.imgOperationInQueue valueForKey:key]) {
ImageOperation *imgOp = [[ImageOperation alloc] initWithItemID:cell.dataItem.ItemID withManufacturerID:cell.dataItem.ManufacturerID withReurnType:kThumbnail];
imgOp.identifier = [NSString stringWithFormat:#"%i", cell.tag];
imgOp.delegate = self;
[[SharedFunctions sharedInstance] addImageOperationToQueue:imgOp];
[imgOp release];
// store these in the dictionary so we don;t queue up requests more than once
[self.imgOperationInQueue setValue:cell.dataItem.ItemID forKey:key];
}
If I could add the delegate as a parameter I could put all of this code into the shared singleton class and call it from anywhere in my app.
I suppose that I could use an NSNotification - or can I use a block of some sort?
Just create the appropriate init method that passes in the delegate.
- (id)initWithItemID:(NSString *)itemID
withManufacturerID:(NSString *)manufacturerID
withReurnType:(NSInteger)type
delegate:(id<YourDelegate>)theDelegate
{
self = [super init];
if (self)
{
.... // Other assignments
self.delegate = theDelegate;
}
return self;
}

Singleton in iOS 5?

Hi I had an implementation previous versions of iOS for a singleton as follows:
.h file
#interface CartSingleton : NSObject
{
}
+(CartSingleton *) getSingleton;
.m file
#implementation CartSingleton
static CartSingleton *sharedSingleton = nil;
+(CartSingleton *) getSingleton
{
if (sharedSingleton !=nil)
{
NSLog(#"Cart has already been created.....");
return sharedSingleton;
}
#synchronized(self)
{
if (sharedSingleton == nil)
{
sharedSingleton = [[self alloc]init];
NSLog(#"Created a new Cart");
}
}
return sharedSingleton;
}
//==============================================================================
+(id)alloc
{
#synchronized([CartSingleton class])
{
NSLog(#"inside alloc");
NSAssert(sharedSingleton == nil, #"Attempted to allocate a second instance of a singleton.");
sharedSingleton = [super alloc];
return sharedSingleton;
}
return nil;
}
//==============================================================================
-(id)init
{
self = [super init];
}
However on the web I see people have implemented the Singleton design pattern using this code:
+ (id)sharedInstance
{
static dispatch_once_t pred = 0;
__strong static id _sharedObject = nil;
dispatch_once(&pred, ^{
_sharedObject = [[self alloc] init]; // or some other init method
});
return _sharedObject;
}
Could someone who is experience please guide me.
Im a newbie and thoroughly confused between the old iOS implementation of the Singleton and the new one and which is the correct one?
Thanks a lot
Strictly speaking, you must use:
+ (MySingleton*) instance {
static dispatch_once_t _singletonPredicate;
static MySingleton *_singleton = nil;
dispatch_once(&_singletonPredicate, ^{
_singleton = [[super allocWithZone:nil] init];
});
return _singleton;
}
+ (id) allocWithZone:(NSZone *)zone {
return [self instance];
}
Now you guarantee that one cannot call alloc/init and create another instance.
Explanation: The instance method is at the class level and is your main access method to get a reference to the singleton. The method simply uses the dispatch_once() built-in queue that will only execute a block once. How does the runtime guarantee that the block is only executed once? Using the predicate you supply (of type dispatch_once_t). This low-level call will guarantee that even if there are multiple threads trying to call it, only one succeeds, the others wait until the first one is done and then returns.
The reason we override allocWithZone is because alloc calls allocWithZone passing nil as the zone (for the default zone). To prevent rogue code from allocating and init-ializing another instance we override allocWithZone so that the instance passed back is the already initialized singleton. This prevents one from creating a second instance.
The dispatch_once snippet is functionally identical to other one. You can read about it at http://developer.apple.com/library/mac/#documentation/Darwin/Reference/Manpages/man3/dispatch_once.3.html.
This is what I use for singletons:
+ (MySingleton*) getOne {
static MySingleton* _one = nil;
#synchronized( self ) {
if( _one == nil ) {
_one = [[ MySingleton alloc ] init ];
}
}
return _one;
}
NOTE: In most cases, you do not even need to use #synchronized (but it is safe this way).
A singleton is a special kind of class where only one instance of the class exists for the current process. (In the case of an iPhone app, the one instance is shared across the entire app.) Some examples in UIKit are [UIApplication sharedApplication] (which returns the sole instance of the application itself), and [NSFileManager defaultManager] (which returns the file manager instance). Singletons can be an easy way to share data and common methods across your entire app.
Rather than create instances of the singleton class using alloc/init, you'll call a class method that will return the singleton object. You can name the class method anything, but common practice is to call it sharedName or defaultName.
Please check a link with best answer
:http://www.idev101.com/code/Objective-C/singletons.html

How can i unit test an object internal to a method in Objective-C?

I'm wondering how to go about testing this. I have a method that takes a parameter, and based on some properties of that parameter it creates another object and operates on it. The code looks something like this:
- (void) navigate:(NavContext *)context {
Destination * dest = [[Destination alloc] initWithContext:context];
if (context.isValid) {
[dest doSomething];
} else {
// something else
}
[dest release];
}
What i want to verify is that if context.isValid is true, that doSomething is called on dest, but i don't know how to test that (or if that's even possible) using OCMock or any other traditional testing methods since that object is created entirely within the scope of the method. Am i going about this the wrong way?
You could use OCMock, but you'd have to modify the code to either take a Destination object or to use a singleton object which you could replace with your mock object first.
The cleanest way to do this would probably be to implement a
-(void) navigate:(NavContext *)context destination:(Destination *)dest;
method. Change the implementation of -(void) navigate:(NavContext *)context to the following:
- (void) navigate:(NavContext *)context {
Destination * dest = [[Destination alloc] initWithContext:context];
[self navigate:context destination:dest];
[dest release];
}
This will allow your tests to call the method with an extra parameter directly. (In other languages, you would implement this simply by providing a default value for the destination parameter, but Objective-C does not support default parameters.)
What i want to verify is that if context.isValid is true, that doSomething is called on dest
I think you may be testing the wrong thing here. You can safely assume (I hope) that boolean statements work correctly in ObjC. Wouldn't you want to test the Context object instead? If context.isValid then you're guaranteed that the [dest doSomething] branch gets executed.
It's completely possible, using such interesting techniques as method swizzling, but it's probably going about it the wrong way. If there's absolutely no way to observe the effects of invoking doSomething from a unit test, isn't the fact that it invokes doSomething an implementation detail?
(If you were to do this test, one way to accomplish your aims would be replacing the doSomething method of Destination with one that notifies your unit test and then passes on the call to doSomething.)
I like to use factory methods in this situation.
#interface Destination(Factory)
+ (Destination *)destinationWithContext:(NavContext *)context;
#end
#implementation Destination(Factory)
+ (Destination *)destinationWithContext:(NavContext *)context
{
return [[Destination alloc] initWithContext:context];
}
#end
I then make a FakeClass:
#import "Destination+Factory.h"
#interface FakeDestination : Destination
+ (id)sharedInstance;
+ (void)setSharedInstance:(id)sharedInstance;
// Note! Instance method!
- (Destination *)destinationWithContext:(NavContext *)context;
#end
#implementation FakeDestination
+ (id)sharedInstance
{
static id _sharedInstance = nil;
if (!_sharedInstance)
{
_sharedInstance = [[FakeDestination alloc] init];
}
return _sharedInstance;
}
+ (void)setSharedInstance:(id)sharedInstance
{
_sharedInstance = sharedInstance;
}
// Overrides
+ (Destination *)destinationWithContext:(NavContext *)context { [FakeDestination.sharedInstance destinationWithContext:context]; }
// Instance
- (Destination *)destinationWithContext:(NavContext *)context { return nil; }
#end
Once you set this up, you just need to swizzle the class methods for + (Destination *)destinationWithContext:(NavContext *)context;
Now you're set to:
id destinationMock = [OCMock mockForClass:FakeDestination.class];
// do the swizzle
[FakeDestination setSharedInstance:destinationMock];
[[destinationMock expect] doSomething];
// Call your method
[destinationMock verify];
This is a fair amount of coding up front, but it's very reusable.

Objective-C Singletons and LLVM/clang leak warnings

I'm using the singleton pattern in several places in an application, and I'm getting memory leak errors from clang when analyzing the code.
static MyClass *_sharedMyClass;
+ (MyClass *)sharedMyClass {
#synchronized(self) {
if (_sharedMyClass == nil)
[[self alloc] init];
}
return _sharedMyClass;
}
// clang error: Object allocated on line 5 is no longer referenced after this point and has a retain count of +1 (object leaked)
I'm using these settings for scan-build:
scan-build -v -v -v -V -k xcodebuild
I'm fairly certain that the code in the singleton is just fine - after all, it's the same code referenced here on Stack Overflow as well as in Apple's documentation - but I would like to get the memory leak warning sorted out so my scan-build returns success.
I may be being exceptionally dense, but surely your line 5
[[self alloc] init];
allocates an object of the containing class type, and promptly throws it away? Do you not want
_sharedMyClass = [[self alloc] init];
?
Apple has since updated their recommended singleton code to pass the static analyzer:
+ (MyGizmoClass*)sharedManager
{
if (sharedGizmoManager == nil) {
sharedGizmoManager = [[super allocWithZone:NULL] init];
}
return sharedGizmoManager;
}
+ (id)allocWithZone:(NSZone *)zone
{
return [[self sharedManager] retain];
}
Now +sharedManager calls super's -allocWithZone: and assigns the return of -init, and the singleton's -allocWithZone: just returns a retained sharedInstance.
Edit:
Why the retain in +allocWithZone:?
+allocWithZone: is overridden because someone using MyGizmoClass could circumvent the singleton by calling [[MyGizmoClass alloc] init] instead of [MyGizmoClass sharedManager]. It's retained because +alloc is expected to always return an object with a retain count of +1.
Every call to +alloc should be balanced with a -release or -autorelease, so without the retain in +allocWithZone:, the shared instance could potentially be deallocated out from under other users.
You may be interested in a simple, one-method, GCD-based singleton implementation (and thus 10.6+ only) posted on Mike Ash's site:
+ (id)sharedFoo
{
static dispatch_once_t pred;
static Foo *foo = nil;
dispatch_once(&pred, ^{ foo = [[self alloc] init]; });
return foo;
}
You are referencing self in a class method! Big no-no! Secondly, you are calling [[self alloc] init] and just throwing away the instance. You should assign the singleton reference in the class method, and not in init like I am guessing you are doing. Next, there is no real guarantee that _sharedMyClass will be initialized to zero. You should explicitly initialize it to nil.
static MyClass *_sharedMyClass = nil;
+ (MyClass *)sharedMyClass {
#synchronized(self) {
if (_sharedMyClass == nil)
_sharedMyClass = [[MyClass alloc] init];
}
return _sharedMyClass;
}
You also probably had this in there too...
+ (id)allocWithZone:(NSZone *)zone {
#synchronized(self) {
if (sharedInstance == nil) {
sharedInstance = [super allocWithZone:zone];
return sharedInstance; // assignment and return on first allocation
}
}
return nil; // on subsequent allocation attempts return nil
}
The reason you weren't storing it in init is because you were storing it in the method that alloc called. This is the pattern Apple has in their examples. If you save the value in your init as well, all is fine and the warning goes away. I'd leave the allocWithZone implementation alone.