This question already has answers here:
Using a singleton to create an array accessible by multiple views
(2 answers)
Closed 9 years ago.
I have created a singleton class in Objective C. Like the one below:
#interface SingletonClass : NSObject{
NSMutableArray *instanceArray;
}
#property(nonatomic,retain)NSMutableArray *instanceArray;
+(SingletonClass*)sharedInstance;
#end
#implementation SingletonClass
#synthesize instanceArray;
static SingletonClass *sharedInstance =nil;
+(SingletonClass*)sharedInstance
{
if(sharedInstance==nil){
sharedInstance=[[super allocWithZone:NULL]init];
}
return sharedInstance;
}
-(id)init{
self=[super init];
if(self){
instanceArray=[[NSMutableArray alloc]init];
[instanceArray addObject:#"One"];
[instanceArray addObject:#"Two"];
}
return self;
}
+(id)allocWithZone:(NSZone *)zone{
return [self sharedInstance];
}
#end
I know it can be accessed from anywhere with the following piece of code:
SingletonClass *singletonObject=[SingletonClass sharedInstance];
And the instanceArray can be accessed anywhere by singletonObject.instanceArray.
Now my question is, is is possible to modify the array by adding new objects to it ? Will that be persisted ? Because i tried to add an object from one class
[singletonObject.instanceArray addObject:#"Three"];
When i checked the array contents from another class, the array consisted of only two values which are initialized by default. The value which i added from another class didnt show up.
What could be the problem ? Am I missing something here ? Please help.
Drop the allocWithZone: implementation entirely. It is prone to error and a distinctly odd thing to do. The reality is that if you have code that is using your singleton class and not going through sharedInstance then that code is broken. Attempting to hide that brokenness is just going to cause pain later.
Just do this one:
+(instancetype)sharedInstance
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[SingletonClass alloc] init];
});
return sharedInstance;
}
If you aren't seeing updates to the array in your other class, then there is some other bug.
Your implementation of allocWithZone: is never called because you are calling the [super allocWithZone:], also i don't think you need this method.
i would change your class method with this:
+(instancetype)sharedInstance
{
if(sharedInstance==nil){
sharedInstance = [[SingletonClass alloc]init];
}
return sharedInstance;
}
and if you want to be more secure that you are not going to create another instance of your object use dispatch_once:
+(instancetype)sharedInstance
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[SingletonClass alloc] init];
}
return sharedInstance;
}
I think that you forgot the ! before self in init method :
-(id)init {
self = [super init];
if(!self) {
instanceArray=[[NSMutableArray alloc]init];
[instanceArray addObject:#"One"];
[instanceArray addObject:#"Two"];
}
return self;
}
That's why each time you get a new instance of your singleton
Related
This question already has answers here:
What should my Objective-C singleton look like? [closed]
(26 answers)
Closed 8 years ago.
I am doing the following in order to initialise my singelton:
ChatDataController *box = [ChatDataController sharedInstance];
The problem is that i use *box in different places, for example in these methods:
- (void) viewDidAppear:(BOOL)animated
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
Is there a way to only have to initialise once? so that *box can be used in any method within a given class?
Put this code in your ChatDataController
+ (ChatDataController *)sharedInstance
{
static ChatDataController *object = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
object = [[ChatDataController alloc] init];
});
return object;
}
Is there a way to only have to initialise once?
If ChatDataController is a singleton it can only be initialised once.
[ChatDataController sharedInstance] should always return the same instance and only alloc] init] the first time it is called.
If, as you mentioned in one of the comments, you already have your singleton, then simply call [ChatDataController sharedInstance] whenever you need the shared instance. There is no need to store the pointer to the object in a property.
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html
In "Creating a Singleton Instance"
static MyGizmoClass *sharedGizmoManager = nil;
+ (MyGizmoClass*)sharedManager
{
if (sharedGizmoManager == nil) {
sharedGizmoManager = [[super allocWithZone:NULL] init];
}
return sharedGizmoManager;
}
try this one:- create macro in .pch file
first import class
#import"ChatDataController.h"
then create macro
(sharedInstance must be class method)
#define box ([ChatDataController sharedInstance])
after that u you can use this object in all classes
I have a singleton class which is allocation object only one time in whole project. Few code line is below..
declaration...
....
MyClassName *classObject = nil
In the init method, the code is like below..
-(id) init(){
self = [super init];
if(classObject == nil){
1. Allocate object code here
2. classObject = self;
3. return classObject
} else {
return classObject;
}
}
But my problem is that how will I dealloc this object. I am calling this init method from all the class and it is returning classObject reference every time.
My approach....
From the dealloc method in appdelegate.m, I am calling a function (releaseObject)which is defined in MyClassName . Here is the definition of function body...
-(void) releaseObject {
[self release]; // Confusion: Will it dealloc classObject reference?
[super release];
}
Is this good idea dealloc this object? My problem is that I don't have to dealloc object until application is not being closed.
The answer is don't bother ever to release the singleton. It is supposed to last the lifetime of the application anyway and will go away automatically along with everything else when the process terminates. You may find that the dealloc method on your app delegate never gets called for the same reason.
If you have clean up to do on application close, it's probably better to move that into a separate method and just call that when the application is about to terminate.
a simpler pattern for a singleton IMO is to have a class method to return the singleton instance and not mess about with releasing stuff in init.
+(MyClass*) sharedInstance
{
static MyClass* theInstance = nil;
static dispatch_once_t pred;
dispatch_once(&pred, ^{ theInstance = [[MyClass alloc] init]});
return theInstance;
}
The above uses dispatch_once to ensure the initialising block only happens once in the lifetime of the application. You can still create other instances by calling init directly but that is advantageous IMO.
I'd recommend to make an extra class method in your singleton:
static MyClassName *classObject = nil;
...
+ (MyClassName *)sharedInstance {
...
}
+ (void)releaseSharedInstance {
[classObject release];
classObject = nil;
}
If your class is a singleton, in AppDelegete dealloc just call
[[YourClass instance] release];
Here is workaround via Objective C++:
class StaticOwner {
private:
id<NSObject> object;
public:
StaticOwner(id<NSObject> obj) { object = [obj retain]; }
~StaticOwner() { [object release]; }
id<NSObject> instance() {return object;}
};
Usage example:
+ (MySingleton*) sharedInstance {
static StaticOwner owner = StaticOwner([[[MySingleton alloc] init] autorelease]);
return owner.instance();
}
suppose I got a singleton class MySingleton as coded below.
Now is a singleton class just like any other class. I can have instance variables that are nonatomic and retain?
I can have: #property (nonatomic, retain) NSString* instanceVar in the .h file
and #synthesize instanceVar in the .m file?
static MySingleton* _sharedMySingleton = nil;
+(MySingleton*)sharedMySingleton
{
#synchronized([MySingleton class])
{
if (!_sharedMySingleton)
[[self alloc] init];
return _sharedMySingleton;
}
return nil;
}
+(id)alloc
{
#synchronized([MySingleton class])
{
NSAssert(_sharedMySingleton == nil, #"Attempted to allocate a second instance of a singleton.");
_sharedMySingleton = [super alloc];
return _sharedMySingleton;
}
return nil;
}
Yes, the instance of a singleton class behaves the same as a standard class, there is just one instance.
The pattern you have is overly complicated, there is no need for +(id)alloc
Here is a simplier pattern:
#implementation MySingleton
static MySingleton* _sharedMySingleton = nil;
+(MySingleton*)sharedMySingleton
{
#synchronized([MySingleton class])
{
if (!_sharedMySingleton)
_sharedSingleton = [[MySingleton alloc] init];
}
return _sharedMySingleton;
}
You bet. To the rest of your application, your singleton looks and works just like any other class. The only difference is that when your application tries to create a new singleton it always receives back the same object. But the singleton can have instance methods and instance variables just like any other class.
Not familiar with the annotations you mentioned because I'm a C++ developer, but a singleton can certainly have instance data. That's one of its values.
Yes you can have instance variables, a singleton is simply a regular class, where there is only one instance at any given time.
For learning iOS programming I'm developing an iPhone application for sharing images. The application is the client for a website.
In the method didFinishLaunchingWithOptions I check if the user is already logged in.
If the user isn't logged in he can still see all parts of the applications but for example he wouldn't see option button for editing profile, comment on images, etc.
How can I share the logged/or not status throughout all view controllers?
Update: If giving this advice today, I would say use a shared instance:
#interface SomeClass: NSObject
{
+(SomeClass *)shared;
}
#implementation SomeClass
{
+(SomeClass *)shared {
static SomeClass *shared;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
shared = [SomeClass new];
});
return shared;
}
}
Then it is auto-instantiated for you on first use, and available throughout your app:
[[SomeClass shared] doSomething];
You can use a singleton - a global, shared instance of an object.
#interface SomeClassSingleton : NSObject {
}
+(SomeClass*)sharedSomeClass;
+(void)setSharedSomeClass:(SomeClass*)someObject;
#end
#implementation SomeClassSingleton
static SomeClass* _someObject = nil;
+(SomeClass*)sharedSomeClass
{
return _someObject;
}
+(void)setSharedSomeClass:(SomeClass*)someObject
{
#syncrhonized(self)
{
_someObject = someObject;
}
}
#end
Then, when you need to access your object in another source file, you import the header file for your singleton in the other header, like you would for any other reference.
Create a singleton:
SomeClass* someObject = [[SomeClass alloc] init];
[SomeClassSingleton setSharedSomeClass:someObject]; // write to save your singleton
Use/read a singleton:
[[SomeClass sharedSomeClass] someSharedClassMessage];
// OR
SomeClass* someObject = [SomeClass sharedSomeClass];
Or, you can create a singleton implementation that auto-inits the first time you access it:
#implementation SomeClassSingleton
static SomeClass* _someObject = nil;
+(SomeClass*)sharedSomeClass
{
#synchronized(self) {
if (_someObject == nil) {
_someObject = [[SomeClass alloc] init];
}
}
return _someObject;
}
#end
Put it in a singleton like the application delegate or as a transient value in a model object (like user data) that everything can see.
If you add an assigned BOOL property to your application delegate, you can get to it like this:
myApplicationDelegate *myDelegate = (myApplicationDelegate*)[[UIApplication sharedApplication] delegate];
myDelegate.userLoggedIn = YES;
I have create a SinglestonClass in my code but i have a problem.
My variable are initialized in the -init method but when i call the singlestonClass these variable are re-initialize.
Can you help me for create a single initialization for my variable?
thanks.
#implementation SingletonController
#synthesize arrayPosition;
#synthesize arrayMovement;
#synthesize actualPosition;
#synthesize actualMove;
#synthesize stopThread;
+(SingletonController*)sharedSingletonController{
static SingletonController *sharedSingletonController;
#synchronized(self) {
if(!sharedSingletonController){
sharedSingletonController = [[SingletonController alloc]init];
}
}
return sharedSingletonController;
}
//I don't want a re-initialization for these variables
-(id)init{
self = [super init];
if (self != nil) {
arrayPosition = [[NSMutableArray alloc]init];
arrayMovement = [[NSMutableArray alloc]init];
actualPosition = [[Position alloc]init];
actualMove = [[Movement alloc]init];
stopThread = FALSE;
}
return self;
}
-(void) dealloc {
[super dealloc];
}
#end
Your init method should not be called by anyone except for your singleton class itself. That's what the sharedSingletonController method is for. This is your factory method that is responsible for returning the same static instance of your class. I'd also suggest that you rename the static instance of your singleton object and/or the sharedSingletonController selector itself to disambiguate between the two and for cleaner design. In this particular case, it may confuse someone who has to read your code.
Without seeing how the client code is calling on your singleton factory method, it's difficult to decipher where your problem is. We'd need to see the rest of the code including how it's being called. In your client code, you should be using something such as:
SingletonController *sigController = [SingletonController sharedSingletonController];
DO NOT DO:
SingletonController *sigController = [[SingletonController alloc] init];
Read here for more information in the Cocoa Fundamentals Guide.