I am currently writing a helper class for my app. The helper class will return globally accessible variables. I created a simple helper as shown below:
#interface MyHelper : NSObject
{
}
+(id) sharedHelper;
+(NSMutableArray *) employers;
+(id) sharedHelper
{
static MyHelper *sharedHelper = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken,^{
sharedHelper = [[self alloc] init];
});
return sharedHelper;
}
+(NSMutableArray *) employers
{
return _employers;
}
Now I can access the employers like this:
[MyHelper employers] and I can also access it like this [[MyHelper sharedHelper] employers] What is the benefit for each approach or they they both same.
I suppose that employers array is a property of your class MyHelper.
If you call [MyHelper employers] without call [MyHelper sharedHelper] you can get incorrect result (the value of employers array is garbage).
Maybe the best practice here is to use lazy loading in +(NSMutableArray *) employers and get static variable out of +(id) sharedHelper:
static MyHelper *sharedHelper = nil;
static dispatch_once_t onceToken;
+(id) sharedHelper
{
dispatch_once(&onceToken,^{
sharedHelper = [[self alloc] init];
});
return sharedHelper;
}
+(NSMutableArray *) employers
{
if(!sharedHelper)
[MyHelper sharedHelper];
return _employers;
}
You employers class method is referencing _employers, which is presumably an instance variable for your class. You cannot do that. Furthermore, even if you did some sloppy workaround, like a global variable, you have no assurances that _employers has been instantiated unless the employers class method also ensures that the sharedHelper is called.
So, a couple of thoughts:
You really should have some class property for employers (I assume you did, but omitted it for brevity, but let's include it here to eliminate ambiguity):
#interface MyHelper : NSObject
#property (nonatomic, strong) NSMutableArray *employers;
#end
I presume your init method would initialize this employers object
- (id)init
{
self = [super init];
if (self) {
_employers = [[NSMutableArray alloc] init];
}
return self;
}
Your existing sharedHelper method is perfectly fine.
If you're going to have an employers class method, though, should access the employers instance method:
+ (NSMutableArray *)employers
{
return [[MyHelper sharedHelper] employers];
}
Having done all of that, your class would look like:
#interface MyHelper : NSObject
#property (nonatomic, strong) NSMutableArray *employers;
+ (id)sharedHelper;
+ (NSMutableArray *)employers;
#end
#implementation MyHelper
+ (id)sharedHelper
{
static MyHelper *sharedHelper = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken,^{
sharedHelper = [[self alloc] init];
});
return sharedHelper;
}
- (id)init
{
self = [super init];
if (self) {
_employers = [[NSMutableArray alloc] init];
}
return self;
}
+ (NSMutableArray *)employers
{
return [[MyHelper sharedHelper] employers];
}
#end
That works, but having said that, as a matter of style, I personally wouldn't recommend a class method, employers, when you have a getter method for a property of the same name. Seems a little confusing. I would excise that employers class method, and stick with the standard getter method that will be synthesized for you, resulting in just:
#interface MyHelper : NSObject
#property (nonatomic, strong) NSMutableArray *employers;
+ (id)sharedHelper;
#end
#implementation MyHelper
+ (id)sharedHelper
{
static MyHelper *sharedHelper = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken,^{
sharedHelper = [[self alloc] init];
});
return sharedHelper;
}
- (id)init
{
self = [super init];
if (self) {
_employers = [[NSMutableArray alloc] init];
}
return self;
}
#end
And then other code using this MyHelper class can simply refer to [[MyHelper sharedHelper] employers] themselves.
Related
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
I've been trying to implement a global NSMutableArray from what I think to be a singleton class that I've implemented.
I can enter ViewController # 2, add and remove objects to the array.
However, when I leave ViewController #2 and come back, the data does not persist, and I have an array with 0 objects.
What do you think I'm doing wrong?
.h
// GlobalArray.h
#interface GlobalArray : NSObject{
NSMutableArray* globalArray;
}
+(void)initialize;
.m
#import "GlobalArray.h"
#implementation GlobalArray
static GlobalArray* sharedGlobalArray;
NSMutableArray* globalArray;
+(void)initialize{
static BOOL initalized = NO;
if(!initalized){
initalized = YES;
sharedGlobalArray = [[GlobalArray alloc] init];
}
}
- (id)init{
if (self = [super init]) {
if (!globalArray) {
globalArray = [[NSMutableArray alloc] init];
}
}
return self;
}
View Controller #2
GlobalArray* myGlobalArray;
myGlobalArray = [[GlobalArray alloc] init];
//Various add and remove code
Thank you for your input.
Following is best approach to share data Globally at Application level. Singleton Class is a key. Singleton is only initialised once, rest of times shared data is returned.
#interface Singleton : NSObject
#property (nonatomic, retain) NSMutableArray * globalArray;
+(Singleton*)singleton;
#end
#implementation Singleton
#synthesize globalArray;
+(Singleton *)singleton {
static dispatch_once_t pred;
static Singleton *shared = nil;
dispatch_once(&pred, ^{
shared = [[Singleton alloc] init];
shared.globalArray = [[NSMutableArray alloc]init];
});
return shared;
}
#end
Following is the way to access/use shared data.
NSMutableArray * sharedData = [Singleton singleton].globalArray;
You create separate instance of GlobalArray in your ViewController#2 with this code:
GlobalArray* myGlobalArray;
myGlobalArray = [[GlobalArray alloc] init];
Instead, you should create accessor method to return your shared instance, something like this:
// GlobalArray.h
#interface GlobalArray : NSObject{
NSMutableArray* globalArray;
}
+(void)initialize;
+(GlobalArray*)sharedInstance;
with implementation:
// GlobalArray.m
// ... your existing code
// accessor method
+(GlobalArray*)sharedInstance
{
return sharedGlobalArray;
}
and then call it from your ViewController#2:
GlobalArray* myGlobalArray = [GlobalArray sharedInstance];
However, using global variables to transfer data between view controllers is bad practice; I suggest you to use more safe methods, create a delegate, for example.
To create a shared global array, if that's really what you want, just put this in the header file:
extern NSMutableArray *myGlobalArray;
and this in your main source file:
NSMutableArray *myGlobalArray;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
myGlobalArray = [NSMutableArray new];
}
Use this code for set and get the array views, for adding and removing do it separate in controller itself.
// GlobalArray.h
#interface GlobalArray : NSObject
#property (nonatomic, strong) NSMutableArray* globalArray;
+ (id)sharedManager;
-(NSMutableArray *) getGlobalArray;
-(void) setGlobalArray:(NSMutableArray *)array;
#end
/*-----------------------------------------*/
#import "GlobalArray.h"
#implementation GlobalArray
+ (id)sharedManager {
static GlobalArray *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
- (id)init{
if (self = [super init]) {
if (!globalArray) {
globalArray = [[NSMutableArray alloc] init];
}
}
return self;
}
-(NSMutableArray *) getGlobalArray{
return self.globalArray;
}
-(void) setGlobalArray:(NSMutableArray *)array{
_globalArray = globalArray;
}
#end
-------------------------
//get array
NSArray * array = [[GlobalArray sharedManager] getGlobalArray];
//set array
[[GlobalArray sharedManager] setGlobalArray:array]
-------------------------
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;
}
I have a complete noob question for you. I'm obviously rusty with obj-c. I have a simple shopping cart class implemented as a singleton and just want it to store a single NSMutableDictionary. I want to be able to add objects to this dictionary from anywhere in the app. But for some (I'm sure simple) reason it's just returning null. No error messages.
ShoppingCart.h:
#import <Foundation/Foundation.h>
#interface ShoppingCart : NSObject
// This is the only thing I'm storing here.
#property (nonatomic, strong) NSMutableDictionary *items;
+ (ShoppingCart *)sharedInstance;
#end
ShoppingCart.m:
// Typical singelton.
#import "ShoppingCart.h"
#implementation ShoppingCart
static ShoppingCart *sharedInstance = nil;
+ (ShoppingCart *)sharedInstance
{
#synchronized(self)
{
if (sharedInstance == nil)
sharedInstance = [[self alloc] init];
}
return(sharedInstance);
}
#end
And in my VC I'm trying to set it with:
- (IBAction)addToCartButton:(id)sender
{
NSDictionary *thisItem = [[NSDictionary alloc] initWithObjects:#[#"test", #"100101", #"This is a test products description"] forKeys:#[#"name", #"sku", #"desc"]];
// This is what's failing.
[[ShoppingCart sharedInstance].items setObject:thisItem forKey:#"test"];
// But this works.
[ShoppingCart sharedInstance].items = (NSMutableDictionary *)thisItem;
// This logs null. Specifically "(null) has been added to the cart"
DDLogCInfo(#"%# has been added to the cart", [[ShoppingCart sharedInstance] items]);
}
Thanks
You are never creating a NSMutableDictionary object named items.
You could create it in the init of ShoppingCart.
-(id)init
{
if(self = [super init]) {
_items = [NSMutableDictionary dictionary];
}
return self;
}
or in sharedInstance
+ (ShoppingCart *)sharedInstance
{
#synchronized(self)
{
if (sharedInstance == nil)
sharedInstance = [[self alloc] init];
sharedInstance.items = [NSMutableDictionary dictionary];
}
return(sharedInstance);
}
I might also add it's better (arguably) to set up your shared instance like so:
static ShoppingCart *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
instance.items = [NSMutableDictionary dictionary];
});
return instance;
I have created a single ton like this for ARC,
+ (MyClass *)sharedInstance {
static MyClass *sharedSpeaker = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedSpeaker = [[self alloc] init];
});
return sharedSpeaker;
}
- (id)init {
if (self = [super init]) {
}
return self;
}
But here I am creating instances like this:
id speaker3 = [[MyClass alloc] init];
id speaker = [MyClass sharedInstance];
id speaker2 = [[MyClass alloc] init];
NSLog(#"Speaker 1= %# \n speaker 2 = %#\n Speaker3 = %#",speaker,speaker2,speaker3);`
I got output as:
Speaker 1= <MyClass : 0xa45f5e0>
speaker 2 = <MyClass : 0xa461740>
Speaker3 = <MyClass : 0xa4529e0>
This is looking like a desired behaviour. How to stop this when I am giving singleton in library to user. I need to block him from creating new instance. Do I need to make static global if I make it global he cant create the global variable of the same name there will be conflict right. So any memebers can give solution on this?
For example using an assert in the init method.
- (id)init {
static int maxInstances = 1;
assert(maxInstances > 0);
maxInstances--;
...
}
Because you are creating new instances of your singleton class using alloc, init.
You will get the singleton instance using the sharedInstance class method. Like:
id speaker = [MyClass sharedInstance];
If you don't want to create the instances with alloc or init. Override those methods.
You can write static MyClass *sharedSpeaker = nil; as a static global variable and remove it from the sharedInstance method.
in .h file
#import <Foundation/Foundation.h>
#interface Singleton : NSObject
{
///......
}
+ (Singleton *)sharedSingleton;
in .m file
#import "Singleton.h"
#implementation Singleton
static Singleton *singletonObj = NULL;
+ (Singleton *)sharedSingleton
{
#synchronized(self)
{
if (singletonObj == NULL)
singletonObj = [[self alloc] init];
}
return(singletonObj);
}
and use this in another file
#import "Singleton.h"
//.....
Singleton *sinObj = [Singleton sharedSingleton]; // not alloc and init. use direct
create instance like this it will always return you singlton
static testSinglton *myinstance = nil;
+ (testSinglton *) sharedInstance {
if (!myinstance) {
myinstance = [[testSinglton alloc] init];
}
return myinstance;
}
- (id) init {
if (myinstance) {
return myinstance;
}
if (self = [super init]) {
//new object now will be created...
myinstance = self;
}
return self;
}
NSLog(#"%#",[[testSinglton alloc] init]);
NSLog(#"%#",[testSinglton sharedInstance]);
NSLog(#"%#",[[testSinglton alloc] init]);