I'm trying to understand the Singleton concept in objective-c.
Most examples that I did found just refer to a single variable.
I'm a bit lost about how to adapt the examples to handle many variables as per an example the accelerometer values that return x, y, z.
Can you guide me a bit further ?
A Singleton refers to a special object that can only exist once inside the lifespan of your application. That object can have as many variables and properties as necessary.
// Singleton.h
#interface Singleton : NSObject
#property (readwrite) int propertyA;
#property (readwrite) int propertyB;
#property (readwrite) int propertyC;
+ (Singleton *)sharedInstance;
#end
The key to a Singleton is that it can only be created once. Usually in Objective-C we use the #synchronized() directive to make sure it only gets created once. We put this in a convenience class method called sharedInstance and return our Singleton. Since the Singleton is just an object it can easily have multiple properties, variables, and methods.
// Singleton.m
#import "Singleton.h"
#interface Singleton ()
{
int variableA;
int variableB;
int variableC;
}
#end
#implementation Singleton
static Singleton *sharedInstance = nil;
+ (Singleton *)sharedInstance
{
#synchronized(self) {
if (sharedInstance == nil) {
sharedInstance = [[Singleton alloc] init];
}
}
return sharedInstance;
}
+ (id)allocWithZone:(NSZone *)zone {
#synchronized(self) {
if (sharedInstance == nil) {
sharedInstance = [super allocWithZone:zone];
return sharedInstance;
}
}
return nil;
}
- (id)init {
self = [super init];
if (self) {
// Inits
}
return self;
}
#end
This is not the ONLY way to create a Singleton. Remember the important part is it can only be created once. So you can take advantage of newer Grand Central Dispatch calls when developing for OSX and iOS such as dispatch_once.
Talking to the Singleton
So lets say you have another object elsewhere talking to the Singleton. This can be done anywhere you #import "Singleton.h"
- (void)someMethod
{
// Setting properties
int valueA = 5;
[[Singleton sharedInstance] setPropertyA:valueA];
// Reading properties
int valueB = [[Singleton sharedInstance] propertyB];
}
Related
As a foray into new programming languages, I build well known data structures to familiarize myself with the syntax and the basic ins & outs of the language. In this case, I examine the stack in Objective-C. From Apple's Working with Objects we read about the keyword 'id'
...This is a special keyword used in Objective-C to mean “some kind of object.” It is a pointer to an object, like (NSObject *), but is special in that it doesn’t use an asterisk.
By using the keyword 'id', it seems possible to create a stack data structure that holds differing types of Obj-C objects; however, I am not sure if this as intended. Is it better to create the various class methods for each potential data type rather than attempting a generic method and make sure each stack adheres to a single Object type?. Here is what I have so far
XYZNode.h
#import <Foundation/Foundation.h>
#interface XYZNode : NSObject
#property id value;
#property XYZNode *next;
-(instancetype)initWithValue:(id)aValue next:(XYZNode *)aNext;
-(instancetype)init;
// Class factory methods should always start with the name of
// the class (without the prefix) that they create, with the
// exception of subclasses of classes with existing factory methods.
+(XYZNode *)nodeWithValue:(id)aValue nextNode:(XYZNode *)aNext;
#end
XYZNode.m
#import "XYZNode.h"
#implementation XYZNode
-(instancetype)initWithValue:(id)aValue next:(XYZNode *)aNext {
if (self = [super init]) {
_value = aValue;
_next = aNext;
} return self;
}
-(instancetype)init {
return [self initWithValue:nil next:nil];
}
+(XYZNode *)nodeWithValue:(id)aValue nextNode:(XYZNode *)aNext {
return [[self alloc] initWithValue:aValue next:aNext];
}
#end
XYZStack.h
#import <Foundation/Foundation.h>
#interface XYZStack : NSObject
-(void)pushValue:(id)aValue;
-(id)popValue;
-(BOOL)isEmpty;
-(instancetype)init;
-(instancetype)initWithValue:(id)aValue;
+(XYZStack *)stackWithValue:(id)aValue;
#end
XYZStack.m
#import "XYZStack.h"
#import "XYZNode.h"
// The extension hides how the values are stored
#interface XYZStack ()
#property XYZNode *lastNodeAdded;
#end
#implementation XYZStack
// Default initializer
-(instancetype)initWithValue:(id)aValue {
if (self = [super init]) {
_lastNodeAdded = nil;
}
if (aValue) {
[self pushValue:aValue];
}
return self;
}
// Call default initializer
-(instancetype)init{
return [self initWithValue:nil];
}
-(BOOL)isEmpty{
return ([self lastNodeAdded] == nil);
}
-(void)pushValue:(id)aValue {
[self setLastNodeAdded:[XYZNode nodeWithValue:aValue nextNode:[self lastNodeAdded]]];
}
-(id)popValue {
id temp = [[self lastNodeAdded] value];
[self setLastNodeAdded:[[self lastNodeAdded] next]];
return temp;
}
+(XYZStack *)stackWithValue:(id)aValue {
return [[self alloc] initWithValue:aValue];
}
#end
Any comments would be appreciated.
Nomaly I used to build a singleton the following recipe:
+ (MyClass *)sharedInstance
{
static MyClass *_sharedInstance = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedInstance = [[self alloc] init];
// Init variables
});
return _sharedInstance;
}
Then I can call methods as following:
[[MyClass sharedInstance] anyInstanceMethod];
But, what happen when any init variables are configurables from outside the class?
My approach is create two class methods, one of them with configurables variables:
+ (MyClass *)sharedInstanceWithVariableOne:(NSString*)aParamOne andVariableTwo:(NSString*)aParamTwo
{
static MyClass *_sharedInstance = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedInstance = [[self alloc] init];
// Init configurables variables
_sharedInstance.paramOne = aParamOne;
_sharedInstance.paramTwo = aParamTwo;
});
return _sharedInstance;
}
And the second one as proxy to this last one with default values:
+ (MyClass *)sharedInstance
{
return [MyClass sharedInstanceWithVariableOne:#"value1" andVariableTwo:#"value2"];
}
So, if you want to use singleton class with configure variables, you should call first of all sharedInstanceWithVariableOne:andVariableTwo and then only sharedInstance.
I think this approach is not the best and I'm looking forward to use others.
Thanks in advance.
Thanks for your fast responses.
As you says, it's not a singleton.
I'm going to use the same behaviour as [NSURLCache setSharedURLCache:]and [NSURLCache sharedURLCache].
Interface
// MyClass.h
#interface MyClass : NSObject
+ (MyClass *)sharedMyClass;
+ (void)setSharedMyClass:(MyClass *)object;
- (id)initWithParamOne:(NSString)p1 andParamTwo:(NSString)p2;
#end
Implementation
// MyClass.m
#interface MyClass ()
#property(nonatomic, strong) NSString *paramOne;
#property(nonatomic, strong) NSString *paramTwo;
#end;
#implementation MyClass
static MyClass *_sharedInstance = nil;
+ (MyClass *)sharedMyClass
{
if (_sharedInstance == nil) {
_sharedInstance = [[MyClass alloc] initWithParamOne:#"value1" andParamTwo:#"value2"];
}
return _sharedInstance ;
}
+ (void)setSharedMyClass:(MyClass *)object
{
_sharedInstance = object;
}
- (id)initWithParamOne:(NSString)p1 andParamTwo:(NSString)p2
{
self = [super init];
if (self) {
_paramOne = p1;
_paramTwo = p2;
}
return self;
}
Then I could use [[MyClass sharedMyClass] anyMethod]
There are many ways to design what you are after with your shared instance. (It is not a singleton as many comments point out, for that there must be only one instance of the class possible. However that said the shared instance pattern is often used as a "poor man's" singleton with no direct calls to any init methods. Back to the question...) Maybe the following will suit you:
+ (void) setSharedInstanceParameterOne:(NSString*)aParamOne
andParameterTwo:(NSString*)aParamTwo
{
MyClass *_sharedInstance = self.sharedInstance;
_sharedInstance.paramOne = aParamOne;
_sharedInstance.paramTwo = aParamTwo;
}
Now you use [MyClass setSharedInstanceParameterOne:p1 andParameterTwo:p2] to set/change the parameters of the shared instance, and [MyClass sharedInstance] (or MyClass.sharedInstance, though some might have a philosophical discussion about that) to access it.
I'm having trouble creating a nice way of passing a collection around to different view controllers. For example, I created a custom class called Message with a bunch of attributes. I want to have a global NSMutableArray of those stored in a global variable of sorts called messages that I can add to or get from anywhere. Everyone on Stackoverflow says not to use your delagate class to store global variables so I created a singleton class called Shared. In there I created a property for the NSMutableArray called messages like this:
#interface Shared : NSObject {
}
#property (nonatomic, retain) NSMutableArray *messages;
+(Shared *) sharedInstance;
#end
And my .h file is (the important part):
#import "Shared.h"
static Shared* sharedInstance;
#implementation Shared
#synthesize messages;
static Shared *sharedInstance = nil;
-(id) init {
self = [super init];
if (self != nil){
}
return self;
}
-(void) initializeSharedInstance {
}
+ (Shared *) sharedInstance{
#synchronized(self) {
if (sharedInstance == nil){
sharedInstance = [[self alloc] init];
[sharedInstance initializeSharedInstance];
}
return (sharedInstance);
}
}
In my other view controller, I first import "Shared.h", then try this:
[[Shared sharedInstance].messages addObject:m];
NSLog([NSString stringWithFormat:#"Shared messages = %#", [Shared sharedInstance].messages]);
It keeps printing null instead of the the collection of m objects. Any thoughts?
You need to have a static variable.
In .h:
#interface Shared : NSObject
{
NSMutableArray *messages;
}
#property (nonatomic, retain) NSMutableArray *messages;
+ (Shared*)sharedInstance;
#end
in .m:
static Shared* sharedInstance;
#implementation Shared
#synthesize messages;
+ (Shared*)sharedInstance
{
if ( !sharedInstance)
{
sharedInstance = [[Shared alloc] init];
}
return sharedInstance;
}
- (id)init
{
self = [super init];
if ( self )
{
messages = [[NSMutableArray alloc] init];
}
return self;
}
A thought:
#synthesize generates setter and getter methods, it doesn't init your variable. Where do you do that? I can't see it in the excerpts you posted.
The following is not an answer to your issue, but instead a suggestion to an alternative approach that (in my opinion) is 'cleaner' in use.
An alternative to using a Singleton to store app-wide could be to define a class with class methods that retrieves values from the NSUserDefaults. This class could be imported into the prefix header (*.pch) so you can access it from every other class in the project.
Methods inside this class could look like this:
inside Settings.h:
// for this example I'll use the prefix for a fictional company called SimpleSoft (SS)
extern NSString *kSSUserLoginNameKey;
+ (NSString *)userLoginName;
+ (void)setUserLoginName:(NSString *)userLoginName;
inside Settings.m:
kSSUserLoginNameKey = #"SSUserLoginNameKey";
+ (NSString *)userLoginName
{
return [[NSUserDefaults standardUserDefaults] valueForKey:kSSUserLoginNameKey];
}
+ (void)setUserLoginName:(NSString *)userLoginName
{
[[NSUserDefaults standardUserDefaults] setValue:userLoginName forKey:kSSUserLoginNameKey];
[[NSUserDefaults standardUserDefaults] synthesize];
}
Of course in a setup like this NSUserDefaults is the singleton that is being accessed through a convenience class. This class acts as a wrapper around the NSUserDefaults singleton. Values can be accessed like this:
NSString userLoginName = [Settings userLoginName];
[Settings setUserLoginName:#"Bob"];
Other objects -like Arrays- could be accessed in much the same way. One thing to be careful with (much the same as with your current approach) is to be careful not to access a class like this from every other class. Components that are intended to be reusable should pass values, so the components of the application don't become too tightly coupled to the settings class.
I know that the whole point of singleton is to instantiate 1 instance of the onject and reuse it, but when it comes to unit testing I want to be able to renew the singleton object before every test.
I tried to use a category to access the singleton object and release it but It's not accessible by categories any idea what's the best way to achieve this?
#implementation SingletonClass
static SingletonClass *singleton;
+ (SingletonClass*)sharedInstance
{
if (!singleton)
{
singleton = [[SingletonClass alloc] init];
}
return singleton;
}
#end
.
#implementation SingletonClass(Unit Testing Additions)
+ (void)killInstance
{
// I get an error here and I cannot access the singleton Object
[singleton release], singleton = nil;
}
#end
By the very definition of singleton, you can't do this.
If it is your class, don't make it a singleton.
If it isn't your class, doing this will fail.
I'm not sure whether this will work, but maybe you could just override the sharedInstance class method and manage the singleton yourself:
#implementation SingletonClass (Unit Testing Additions)
static SingletonClass *myVeryOwnSharedInstance;
+ (SingletonClass *) sharedInstance
{
if (!myVeryOwnSharedInstance)
myVeryOwnSharedInstance = [[self alloc] init];
return myVeryOwnSharedInstance;
}
+ (void) killInstance
{
[myVeryOwnSharedInstance release];
// if release is overridden to do no-op, maybe just invoke -dealloc directly
myVeryOwnSharedInstance = nil;
}
#end
If you want access to your singleton global variable outside of the file in which it's declared, you'll need to make it globally accessible using extern.
At the top of SingletonClass.h, put this:
extern SingletonClass *singletonClassSingleton;
In your SingletonClass.m, use this:
SingletonClass *singletonClassSingleton = nil;
Then assuming you have #import "SingletonClass.h" in your unit test .m file, you should be able to add:
#implementation SingletonClass(Unit Testing Additions)
+ (void)killInstance
{
[singletonClassSingleton release], singletonClassSingleton = nil;
}
#end
The reason I've renamed singleton to singletonClassSingleton is that the variable is now global - if you have a bunch of singleton classes, you need these variables to have unique names, like dataManagerSingleton, resourceManagerSingleton or whatever.
Here is my own solution.
#implementation SingletonClass(Unit Testing Additions)
//Override
static SingletonClass *singleton;
+ (void)killInstance
{
// I get an error here and I cannot access the singleton Object
[singleton release], singleton = nil;
}
//Override
+ (SingletonClass*)sharedInstance
{
if (!singleton)
{
singleton = [[SingletonClass alloc] init];
}
return singleton;
}
#end
I am trying to implement a class, that subclasses NSObject directly, that can only have one instance available throughout the entire time the application using it is running.
Currently I have this approach:
// MyClass.h
#interface MyClass : NSObject
+(MyClass *) instance;
#end
And the implementation:
// MyClass.m
// static instance of MyClass
static MyClass *s_instance;
#implementation MyClass
-(id) init
{
[self dealloc];
[NSException raise:#"No instances allowed of type MyClass" format:#"Cannot create instance of MyClass. Use the static instance method instead."];
return nil;
}
-(id) initInstance
{
return [super init];
}
+(MyClass *) instance {
if (s_instance == nil)
{
s_instance = [[DefaultLiteralComparator alloc] initInstance];
}
return s_instance;
}
#end
Is this the proper way to accomplish such a task?
Thanks
You need to do a little more than that. This describes how an objective-c singleton should be implemented: Objective-C Singleton
In your scenario, there is still a way to create a second instance of your class:
MyClass *secondInstance = [[MyClass alloc] initInstance]; //we have another instance!
What you want is to override your class's +(id)alloc method:
+(id)alloc{
#synchronized(self){
NSAssert(s_instance == nil, #"Attempted to allocate a second instance of singleton(MyClass)");
s_instance = [super alloc];
return s_instance;
}
return nil;
}