where should I declare the static instance? - ios

what is the difference between these singleton implementations:
declaring static instance outside the sharedManager functions
#implementation MyManager
static MyManager * manager = nil;
+(instancetype)sharedManager
{
#synchronized(self) {
if(manager==nil){
manager = [[MyManager alloc]init];
}
return manager;
}
}
2.
declaring static instance inside the sharedManager function
#implementation MyManager
+(instancetype)sharedManager
{
static MyManager * manager = nil;
#synchronized(self) {
if(manager==nil){
manager = [[MyManager alloc]init];
}
return manager;
}
}
#end
declaring MyManager as extern in the interface
4.
+ (instancetype)sharedManager {
static MyManager *singleton=nil;
static dispatch_once_t once;
dispatch_once(&once, ^{
singleton = [[self alloc] init];
});
return singleton;
}

You should make it a static variable inside the accessor method. This prevents you from accidentally accessing it before it's been properly initialized.
The modern way to initialize a singleton safely is like this:
+ (instancetype)sharedManager {
static MyManager *singleton;
static dispatch_once_t once;
dispatch_once(&once, ^{
singleton = [[self alloc] init];
});
return singleton;
}
dispatch_once is significantly faster than #synchronized if the once-block has already been performed.

Related

How to distinguish between the setter method and the getter method when using macros in Objc?

Inside the method testUser
#define TESTMacro [TestClass shared].testProperty
#interface TestClass:NSObject
#property (nonatomic,strong)NSString* testProperty;
+ (TestClass*)shared;
#end
#implementation TestClass
+(TestClass *)shared{
static TestClass *shared = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
shared = [[TestClass alloc] init];
});
return shared;
}
-(void)testUser{
TESTMacro = #"1"; //setter
NSString *result = TESTMacro;//getter
}
#end
For some reasons, I can't override the setter and getter, so I plan to judge in the macro, and then do different things.But don't know how.

How to check if a Singleton is already initialized?

I have a Singleton class in Objective-C. I want to know if the shared object is already initialized or not, before accessing sharedInstance. How can I do so?
+ (id)sharedInstance {
static MyObject *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (id)init {
if (self = [super init]) {}
return self;
}
I can think of 2 possible ways:
First approach: Move static MyObject *sharedInstance = nil; outside of the method. It will look like:
#implementation MyObject
static MyObject *sharedInstance = nil;
+ (id)sharedInstance {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
+ (BOOL)isSharedInstanceInitialized {
return sharedInatance != nil;
}
- (id)init {
if (self = [super init]) {}
return self;
}
#end
Second approach: As suggested in the comments above to use additional BOOL static value
#implementation MyObject
static BOOL isInitialized = NO;
+ (id)sharedInstance {
static MyObject *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
isInitialized = YES;
});
return sharedInstance;
}
+ (BOOL)isSharedInstanceInitialized {
return isInitialized;
}
- (id)init {
if (self = [super init]) {}
return self;
}
#end

Make one method in view controller globally and call it to many view controllers

I want to make one single method and call it, to many view controllers. Help me? and i also want to alloc UIView or button or label on that Fixed View.
HERE IS MY CODE
.h
#import <UIKit/UIKit.h>
#interface UIOnlyView : UIView
+ (UIOnlyView *) sharedGlobalClass;
-(void)yourMethod;
#end
.m
+(UIOnlyView *)sharedGlobalClass {
static dispatch_once_t pred;
static id shared = nil;
dispatch_once(&pred, ^{
shared = [[super alloc] init];
});
return shared;
}
-(void)yourMethod{
NSLog(#"Method called");
UIView *customView=[[UIView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];
customView.backgroundColor=[UIColor redColor];
[self addSubview:customView];
}
But my Custom view is not show on my view controller class where i called this method.
Use a singleton like this
create a class for example GlobalClass with type NSObject
In .h class create this method
+ (GlobalClass *) sharedGlobalClass;
- (void) yourMethod : (UIView *) view;
Now in .m class
+ (GlobalClass *) sharedGlobalClass {
static dispatch_once_t pred;
static id shared = nil;
dispatch_once(&pred, ^{
shared = [[super alloc] init];
});
return shared;
}
- (void) yourMethod : (UIView *) view {
UIView *customView=[[UIView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];
customView.backgroundColor=[UIColor redColor];
[view addSubview:customView];
}
Now you can call this method like this
[[GlobalClass sharedGlobalClass] yourMethod:self.view];
from any of your ViewController, you just have to import
#import "GlobalClass.h"
In Objective C:
#interface OUCSCalendarManager ()
- (void)globalMethod;
#end
#implementation OUCSCSharedManager
/// ------------------------------------------------------------------------
/// Singleton Method
///--------------------------------------------------------------------------
+(instancetype)SharedManager{
#synchronized(self) {
static OUCSCalendarManager *sharedInstance = nil;
static dispatch_once_t pred;
#synchronized (self) {
dispatch_once(&pred, ^{
sharedInstance = [[OUCSCalendarManager alloc]init];
});
return sharedInstance;
}
}
}
- (void)globalMethod {
}
}
To Call That method from anywhere in project you need to create the singleton object and call method like this
[[OUCSCalendarManager calendarSharedManager]globalMethod];
Let me know if you face any issue.
ClassA.h
#import "ClassA.h"
#interface ClassA : NSObject
+(id)sharedInstance;
-(void)customMethod;
#end
Now Implementation of ClassA.m
#import "ClassA.h"
#implementation ClassA
+(id)sharedInstance
{
static ClassA *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[ClassA alloc] init];
});
return instance;
}
-(void)customMethod
{
//Method body
}
Now import the header file in other viewcontrollers and use it like
[[ClassA sharedInstance] customMethod{}];
You can use the singleton class for this purpose:
create a NSObject class:
import <foundation/Foundation.h>
#interface MyManager : NSObject {
NSString *someProperty;
}
#property (nonatomic, retain) NSString *someProperty;
+ (id)sharedManager;
#end
In your .m file:
import "MyManager.h"
#implementation MyManager
#synthesize someProperty;
+ (id)sharedManager {
static MyManager *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
you can use the someProperty globally in all class.
it defines a static variable initialised once and only once in sharedManager.
for more info: http://www.galloway.me.uk/tutorials/singleton-classes/
https://code.tutsplus.com/articles/design-patterns-singletons--cms-23886

Singleton Object in iOS [duplicate]

This question already has answers here:
Singleton in iOS Objective C doesn't prevent more than one instance
(9 answers)
Closed 7 years ago.
As we know that a singleton object can be instantiated only once and we use singletons in objective C to have a global access to shared resources. We also know that singletons are instantiated using the following method.
+ (instancetype)sharedManager
{
static PhotoManager *sharedPhotoManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedPhotoManager = [[[self class] alloc] init];
sharedPhotoManager->_photosArray = [NSMutableArray array];
});
return sharedPhotoManager;
}
But I can also do this -
PhotoManager *sharedManager = [[PhotoManager alloc] init];
Now this way I can also create another instance of the same singleton class then how come the class is singleton if it is having two instances.
Please clarify.
You can forbid calls of init with such trick:
add - (instancetype)init NS_UNAVAILABLE; definition to your singleton interface.
Instead of [[PhotoManager alloc] init]; use [[[self class] alloc] init];
PhotoManager *sharedManager = [[PhotoManager alloc] init]; won't compile.
There is my example:
#interface SomeSingleton : NSObject
+ (instancetype)sharedInstance;
- (instancetype)init NS_UNAVAILABLE;
#end
#implementation SomeSingleton
+ (instancetype)sharedInstance {
static dispatch_once_t onceToken;
static SomeSingleton *instance;
dispatch_once(&onceToken, ^{
instance = [[[self class] alloc] init];
});
return instance;
}
- (instancetype)init {
self = [super init];
return self;
}
#end
As result SomeSingleton *s1 = [SomeSingleton sharedInstance]; works, but SomeSingleton *s2 = [[SomeSingleton alloc] init]; leads to the compile error.
You have singleton behaviour for object only when you use sharedManager: class method. All other ways you instantiate object are not guaranteed to produce singleton object.
Objective-C allows you to do lots of things that may not be intended. Like calling a private method if you know the method name.
If you are obsessed to make sure your class is only used as singleton, maybe something like this would be of use:
static PhotoManager *sharedPhotoManager = nil;
+ (instancetype)sharedManager
{
if (!sharedPhotoManager) {
sharedPhotoManager = [[PhotoManager alloc] init];
}
return sharedPhotoManager;
}
- (instancetype)init {
if (sharedPhotoManager) {
// init method is allowed to return different object
return sharedPhotoManager;
}
self = [super init];
if (self) {
}
return self;
}
When you write
PhotoManager *sharedManager = [[PhotoManager alloc] init];
you are not getting your sharedInstance, you are creating a new one. The way you should use it is
[PhotoManager sharedInstance];
instead of
PhotoManager *sharedManager = [[PhotoManager alloc] init];
When you create a singleton class you has never use alloc init, you always should use sharedInstance method to keep the same instance in your app
By the way... as T_77 suggest you, you should use dispatch_once instead of your implementation to create an instance.
+ (instancetype)sharedInstance
{
static dispatch_once_t once;
static id sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}

Creating a singleton and overriding the alloc class method

I've created a singleton class using this code:
static MyClass *sharedMyClass = nil;
+ (id)getInstance {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyClass = [[self alloc] init];
});
return sharedMyClass;
}
my concern is that the users of my class can call the alloc method an create other instantiations of the class. Therefore this would no longer be a singleton Do I need to override the alloc method? If so I suggest overriding it this way:
+ (id)alloc
{
id instance = sharedMyClass;
if (instance == nil) {
instance = [super alloc];
}
return instance;
}
Implement it this way?
+(id)alloc
{ #synchronized([MyClass class])
{
NSAssert(_sharedMyClass == nil, #"Attempted to allocate a second instance of a singleton.");
_sharedMyClass = [super alloc];
return _sharedMyClass;
}
return nil;
}
Yes, you need to overwrite the alloc methode.
You can archive this by implementing
+ (instancetype)sharedInstance {
static MyClass *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[super allocWithZone:NULL] init];
});
return sharedInstance;
}
+ (id)allocWithZone:(NSZone *)zone {
return [self sharedInstance];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
Apple provides a detailed description for this case which you can find here (non ARC description) https://developer.apple.com/legacy/library/documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html#//apple_ref/doc/uid/TP40002974-CH4-SW32
You can forbid alloc at compile time:
+ (instancetype)new NS_UNAVAILABLE;
+ (instancetype)alloc NS_UNAVAILABLE;
Using super alloc in your own implementation:
+ (instancetype)getInstance {
static id sharedMyClass
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyClass = [[super alloc] init];
});
return sharedMyClass;
}
It doesn't protect you from some runtime code, but it's clear enough.

Resources