Linking an object between 2 classes objective c? - objective-c

I have 2 View Controllers that contain data about an object, which I want to save as a favourite. Both controllers contain the same type of object < Release > which I want to save in a Favourite class.
The Favourite class is fairly simple, it has 3 functions addFavourite, removeFavourite and getFavourites. What I want to accomplish is that both View Controllers can add objects to the Favourite class and get the favouriteObjects array from the Favourite object.
What I tried was making the Favourite class static, like this:
#implementation Favourites
static Favourites * favourites = nil;
-(id)init {
if(favourites == nil) {
if((favourites = [super init])) {
return favourites;
}
}
return favourites;
}
#end
However, everytime I try to add a favourite from one view controller, it doesn't find it in the other. Anyway to solve this?
Yours Faithfully,
Sem Wong.
If you require more information, please ask, I'm new to this place so I'm not sure how much info you guys need :).
Edit:
Thank you guys for the great answers. I'm trying all of them to see what fits me best. What I've got now seems to work well.
Edit 2:
Seems like I can't upvote anything yet hehe :). Thanks Wain and Lithu T.V and Anum90 for the great answers :).

You may be looking for the singleton instance
How i use it
+(Favourites *)sharedInstance
{
static Favourites*_sharedClient = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedClient = [[Favourites alloc]init];
});
return _sharedClient;
}
you can call it in your classes as
[Favourites sharedInstance];
This will return you an object which is initialised once and return that instance whenever called

Try structuring the favourites class like this:
#implementation Favourites
- (Favourites *)sharedFavourites
{
static dispatch_once_t pred = 0;
__strong static id _sharedObject = nil;
dispatch_once(&pred, ^{
_sharedObject = [[self alloc] init];
});
return _sharedObject;
}
-(id)init {
self = [super init];
return self;
}
#end
Then all controllers that need access to the favoutires should call [Favourites sharedFavourites] to get the instance (no controller should call init).

You need to make Favorites a singleton class, that will return one & same instance all the time. After that , you can access this object from anywhere in your project.
#interface Favourites : NSObject
+(Favourites *)sharedManager;
#end
#implementation Favourites
static Favourites *instance = nil;
+ (Favourites *)sharedManager {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (instance == nil){
instance = [[self alloc] init];
}
});
return instance;
}
-(id) init
{
if ( self = [super init] ) {
}
return self;
}
+ (id)allocWithZone:(NSZone *)zone
{
return [self sharedManager];
}
-(void) addFavorite
{
//Do anything or pass any data by making function with argument
}
#end
Anywhere, you can call it after importing as,
[[Favourites sharedManager] addFavorite];
If you will call Favourite from anywhere and it has been not allocated before, it will automatically call init and allocate you an object. Every next time you call it, it will return same allocated instance.

Related

Singleton Not Instantiating Correctly

I'm playing around with idea of singleton cache. The setup is quite simple:
In my singleton class, I am instantiating one instance as follows:
+(SharedInstanceTest*)sharedInstace
{
static SharedInstanceTest *sharedInstace=nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstace=[[SharedInstanceTest alloc]init];
});
NSLog(#"Share Instance Allocated");
return sharedInstace;
}
+(id)allocWithZone:(NSZone *)zone
{
return [self sharedInstace];
}
Now in the rootViewController, I am calling the sharedInstance just so that I can see the NSLog to make sure it has been instantiated.
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[SharedInstanceTest sharedInstace];
}
I get no NSLog. Any idea why?
Do not override allocWithZone. It is probably causing a loop or something when you do [SharedInstanceTest alloc].
You can override allocWithZone: in order to prevent clients from creating more instances. You just can't use alloc to create the shared instance, because that will end up calling allocWithZone:; then you have an infinite loop, as SB. answered.
You can do something like this (to convert to ARC, just remove the retain in allocWithZone:):
#import "MySingleton.h"
static MySingleton * defaultMySingleton = nil;
//MySingleton * defaultMySingleton = nil;
//void initialize_defaultMySingleton(void) {
// [MySingleton defaultMySingleton];
//}
#implementation MySingleton
+ (MySingleton *)defaultMySingleton {
// Create the instance if it has not been already.
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// Call super's implementation because allocWithZone: is overridden
// to call defaultMySingleton
// The class owns this instance.
defaultMySingleton = [[super allocWithZone:NULL] init];
});
return defaultMySingleton;
}
+ (id)allocWithZone:(NSZone *)zone {
// Users of alloc, although they shouldn't be using this,
// will expect a +1 retain count. Bump it to allow for eventual release.
return [[self defaultMySingleton] retain];
}
- (id)init
{
// If defaultMySingleton exists, then it is self here. Just return it.
if( defaultMySingleton ) return defaultMySingleton;
// Otherwise, do normal setup.
self = [super init];
if( !self ) return nil;
return self;
}
#end
This was inspired by Peter Hosey's singleton blog post, though he seems to have changed his implementation quite a bit since I last read it.

Singleton gets deallocated

I've created a simple singleton class to hold static data for my projects.
The first time I access this singleton is onEnter method in my Cocos2d scene. However when I try to access it again later in another method (same scene) this singleton is already released. I'm confused, how do I keep my singleton from being deallocated?
Here's my singleton's interface part:
#import <Foundation/Foundation.h>
#interface OrchestraData : NSObject
+(OrchestraData *)sharedOrchestraData;
#property (retain, readonly) NSArray *animalNames;
#end
Implementation:
#import "OrchestraData.h"
#implementation OrchestraData
#synthesize animalNames = animalNames_;
+(OrchestraData*)sharedOrchestraData
{
static dispatch_once_t pred;
static OrchestraData *_sharedOrchestraData = nil;
dispatch_once(&pred, ^{ _sharedOrchestraData = [[OrchestraData alloc] init]; });
return _sharedOrchestraData;
}
-(id)init {
if (self = [super init]) {
animalNames_ = [NSArray arrayWithObjects:#"giraffe", #"giraffe", #"giraffe", #"giraffe", nil];
}
return self;
}
#end
I'm using my singleton this way:
[[OrchestraData sharedOrchestraData] animalNames];
Update:
I took a fresh look into it with NSZombies enabled, it appears as if my NSArrays were released, not the singleton itself. What do I do?
You must implement your singleton in this way:
1) in .h file of your Singleton Class:
+ (SingletonClass *)instance;
2) in .m file:
+ (SingletonClass *)instance {
static SingletonClass* instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
//your init code here
});
return instance;
}
If you want to call your singleton, just call [SingletonClass instance].
If your are interesting what is "dispatch_once_t", read about Grand Central Dispatch:
http://developer.apple.com/library/ios/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
RE Update:
Your NSArray deallocates because you're using the autorelease initializer arrayWithObjects and you assign it directly to the ivar animalNames_. Therefore it is not retained.
To fix this, assign the array to the property:
self.animalNames = [NSArray arrayWithObjects:#"giraffe", #"giraffe", #"giraffe", #"giraffe", nil];
Btw, under ARC this wouldn't have been an issue since the ivar would have been a strong (retaining) reference. I don't get tired encouraging anyone to switch to ARC. It's been available for well over a year now and there's absolutely no point in using MRC code anymore! It really pains me to see how developers still don't use the easier, faster, and straightforward option. (rant off) :)
You setup a pointer wherever you need it.
-(void)someMethod {
MySingleton *singleton = [MySingleton sharedSingleton];
singleton.data = YES; //dumb example to show you did something...
}
-(void)someOtherMethod {
MySingleton *singleton = [MySingleton sharedSingleton]; //You have to create a new pointer...
singleton.data = NO; //another dumber example to show you did something...
}
Note: this assumes that you have created a singleton the same way I have... your code might be different therefore causing my answer not to apply...
You need to overwrite the below method inside your singleton class, because in your program, if someone has initialised [[SingletonClass alloc] init] then singleton will have another instance and release it will cause an error.
+ (id)allocWithZone:(NSZone *)zone{
return [[self SingletonClass] retain];
}
- (id)copyWithZone:(NSZone *)zone{
return self;
}
- (id)retain{
return self;
}

Singleton confusion in Objective-C

Consider this code:
+(id)sharedInstance
{
static dispatch_once_t pred;
static MyClass *sharedInstance = nil;
dispatch_once(&pred, ^{
sharedInstance = [[MyClass alloc] init];
});
return sharedInstance;
}
If I follow this singleton design pattern I can make the following assumptions:
The allocation and initialization will only be executed once thanks
to GCD.
The sharedInstance class variable can only be accessed from
within this implementation and shared among the class regardless of the instance.
First time I create the instance I would do something like:
MyClass *something = [MyClass sharedInstance];
my question is, If I call the previews code again but like this:
MyClass *somethingOther = [MyClass sharedInstance];
I can only think of one outcome.
Outcome:
static MyClass *sharedInstance = nil;
Makes sharedInstance class variable point to nil and a nil is returned so somethingOther will be nil.
But I thought that what was supposed to happen in a singleton is that the shared instance would be returned instead.
Now consider this code:
+ (MotionManagerSingleton*)sharedInstance {
static MotionManagerSingleton *_sharedInstance;
if(!_sharedInstance) {
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedInstance = [[super allocWithZone:nil] init];
});
}
return _sharedInstance;
}
+ (id)allocWithZone:(NSZone *)zone {
return [self sharedInstance];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
Here the
static MotionManagerSingleton *_sharedInstance;
Doesnt set my variable to nil, but i thought that all object pointers are initialized to nil by default.
My question is, how are these class methods returning the "sharedInstance"?
Thanks
One. Non-initialized pointers are non-initialized.
static MotionManagerSingleton *_sharedInstance;
won't make your MotionManagerSingleton point to nil. It will point to an undefined (garbage) location.
Two. Variables declared static are initialized only once (yes, the syntax is a bit inconsistent with the semantics), so your first implementation won't null out the returned shared instance. That's a perfectly fine implementation.

Objective-C, class identity

I have the following situation, i can't resolve:
#interface Deck : NSObject
#interface MasterDeck : Deck
#interface PlayerDeck : Deck
Inside MasterDeck class, as part of initialization, i call
[self cutDeckImageIntoCards]; // We don't get to execute this method
Call results in an error [PlayerDeck cutDeckImageIntoCards]: unrecognized selector sent to instance
Indeed, PlayerDeck does not have this method .. but why is it being called at all?
After looking at MasterDeck's initialization i added a few debugging statements:
static MasterDeck *gInstance = NULL;
+(MasterDeck *) instance {
#synchronized(self) {
if (gInstance == NULL) {
gInstance = [[self alloc] init];
}
}
return gInstance;
}
-(id) init {
if (gInstance != NULL) {
return gInstance;
}
// MasterDeck
self = [super init];
// PlayerDeck
if (self) {
// Lots of stuff
[self cutDeckImageIntoCards]
// Some more stuff
}
gInstance = self;
return gInstance;
}
Ok, so MasterDeck is PlayerDeck because' Deck thinks it is a PlayerDeck ... Deck confirms
Deck is created as follows:
static Deck *gInstance = NULL;
+(Deck *) instance {
#synchronized(self) {
if (gInstance == NULL) {
gInstance = [[self alloc] init];
}
}
return gInstance;
}
-(id) init {
if (gInstance != NULL) {
return gInstance;
}
self = [super init];
if (self) {
// Do something
}
NSLog(#"Deck thinks it's a %#", [[self class ]description]); // PlayerDeck
gInstance = self;
return gInstance;
}
So, again
#interface Deck : NSObject
Assuming above Singleton Implementation, why would Deck think it's actually a PlayerDeck?
So the way you've written this, if you create the PlayDeck instance first, then the Deck instance is now a PlayDeck.
And then if you go to create the MasterDeck instance, your call to [super init] dutifully returns that previous PlayDeck instance.
So why is Deck a singleton at all? Deck has two subclasses that are singletons, but are you really looking for a singleton Deck also?
At a minimum, you can make this sort of work by not setting gInstance from within each init. Let the class method do that. Just return self from each of the init's. Also, remove the check for gInstance being not null, other Deck's init will always return Deck's instance once you have an instance of Deck.
But beyond that, I would rethink this idea a bit. Hope that helps.
You'll probably want to separate your singleton class from the actual class.
Try implementing it as in this example,
+(id) instance {
static dispatch_once_t pred;
static MasterDeck *sharedInstance = nil;
dispatch_once(&pred, ^{
sharedInstance = [[MasterDeck alloc] init];
});
return sharedInstance;
}
What happens if you replace [[self alloc] init] with [[MasterDeck alloc] init]?
It may be that somehow self is PlayerDeck. To make sure, you could NSLog([self description]) just before calling + alloc.
Edit
I assume that the interesting part of the code you have above is part of the #implementation of MasterDeck. My suggestion would be to try a lot more logging, including determining what super and [self class] are before calling [super init], although these may be misleading...
Also, as a side note, I believe that you should call [self release] in init if you are returning the previously-created instance.
What does the [super init] method look like? Can you step into it, or is it the default initializer?
Edit 2
I think you're doing singletons wrong. If you initialize a PlayerDeck, that would create a singleton in Deck which is an instance of PlayerDeck. Then later, when you initialize a MasterDeck, calling [super init] will return the instance already created by the PlayerDeck.
It looks like you try to be clever, but fact is - often the computer is even smarter. :)
Your deck class caches an instance in gInstance - in fact, it looks like it may store a Deck, a PlayerDeck, or a MasterDeck, depending on what and how you call / instantiate first. After that, this very instance is returned by that init method.
I strongly suggest to get this code clean and readable. I bet there are numerous problems with this code - but your problem is already a good example. Your logic (which should be simple, I guess) can surely be implemented much easier.
Note - I'm not against singletons, but this sort of code stacking is an absolute no-go. It's hard to get more dependency logic into those lines. ;)

How do I implement an Objective-C singleton that is compatible with ARC?

How do I convert (or create) a singleton class that compiles and behaves correctly when using automatic reference counting (ARC) in Xcode 4.2?
In exactly the same way that you (should) have been doing it already:
+ (instancetype)sharedInstance
{
static MyClass *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[MyClass alloc] init];
// Do any other initialisation stuff here
});
return sharedInstance;
}
if you want to create other instance as needed.do this:
+ (MyClass *)sharedInstance
{
static MyClass *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[MyClass alloc] init];
// Do any other initialisation stuff here
});
return sharedInstance;
}
else,you should do this:
+ (id)allocWithZone:(NSZone *)zone
{
static MyClass *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [super allocWithZone:zone];
});
return sharedInstance;
}
This is a version for ARC and non-ARC
How To use:
MySingletonClass.h
#interface MySingletonClass : NSObject
+(MySingletonClass *)sharedInstance;
#end
MySingletonClass.m
#import "MySingletonClass.h"
#import "SynthesizeSingleton.h"
#implementation MySingletonClass
SYNTHESIZE_SINGLETON_FOR_CLASS(MySingletonClass)
#end
This is my pattern under ARC.
Satisfies new pattern using GCD and also satisfies Apple's old instantiation prevention pattern.
#implementation AAA
+ (id)alloc
{
return [self allocWithZone:nil];
}
+ (id)allocWithZone:(NSZone *)zone
{
[self doesNotRecognizeSelector:_cmd];
abort();
}
+ (instancetype)theController
{
static AAA* c1 = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
c1 = [[super allocWithZone:nil] init];
// For confirm...
NSLog(#"%#", NSStringFromClass([c1 class])); // Prints AAA
NSLog(#"%#", #([c1 class] == self)); // Prints 1
Class real_superclass_obj = class_getSuperclass(self);
NSLog(#"%#", #(real_superclass_obj == self)); // Prints 0
});
return c1;
}
#end
Read this answer and then go and read the other answer.
You must first know what does a Singleton mean and what are its requirements, if you don't understand it, than you won't understand the solution--at all!
To create a Singleton successfully you must be able to do the following 3:
If there was a race condition, then we must not allow multiple instances of your SharedInstance to be created at the same time!
Remember and keep the value among multiple invocations.
Create it only once. By controlling the entry point.
dispatch_once_t helps you to solve a race condition by only allowing its block to be dispatched once.
Static helps you to “remember” its value across any number of
invocations. How does it remember? It doesn't allow any new instance with that exact name of your sharedInstance to be created again it just works with the one that was created originally.
Not using calling alloc init (i.e. we still have alloc init methods since we are an NSObject subclass, though we should NOT use them) on our sharedInstance class, we achieve this by using +(instancetype)sharedInstance, which is bounded to only be initiated once, regardless of multiple attempts from different threads at the same time and remember its value.
Some of the most common system Singletons that come with Cocoa itself are:
[UIApplication sharedApplication]
[NSUserDefaults standardUserDefaults]
[NSFileManager defaultManager]
[NSBundle mainBundle]
[NSOperations mainQueue]
[NSNotificationCenter defaultCenter]
Basically anything that would need to have centralized effect would need to follow some sort of a Singleton design pattern.
Alternatively, Objective-C provides the +(void)initialize method for NSObject and all its sub-classes. It is always called before any methods of the class.
I set a breakpoint in one once in iOS 6 and dispatch_once appeared in the stack frames.
Singleton Class : No one can create more than one object of class in any case or through any way.
+ (instancetype)sharedInstance
{
static ClassName *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[ClassName alloc] init];
// Perform other initialisation...
});
return sharedInstance;
}
// You need need to override init method as well, because developer can call [[MyClass alloc]init] method also. that time also we have to return sharedInstance only.
-(MyClass)init
{
return [ClassName sharedInstance];
}
There are two issues with the accepted answer, which may or may not be relevant for your purpose.
If from the init method, somehow the sharedInstance method is called again (e.g. because other objects are constructed from there which use the singleton) it will cause a stack overflow.
For class hierarchies there is only one singleton (namely: the first class in the hierarchy on which the sharedInstance method was called), instead of one singleton per concrete class in the hierarchy.
The following code takes care of both of these problems:
+ (instancetype)sharedInstance {
static id mutex = nil;
static NSMutableDictionary *instances = nil;
//Initialize the mutex and instances dictionary in a thread safe manner
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
mutex = [NSObject new];
instances = [NSMutableDictionary new];
});
id instance = nil;
//Now synchronize on the mutex
//Note: do not synchronize on self, since self may differ depending on which class this method is called on
#synchronized(mutex) {
id <NSCopying> key = (id <NSCopying>)self;
instance = instances[key];
if (instance == nil) {
//Break allocation and initialization into two statements to prevent a stack overflow, if init somehow calls the sharedInstance method
id allocatedInstance = [self alloc];
//Store the instance into the dictionary, one per concrete class (class acts as key for the dictionary)
//Do this right after allocation to avoid the stackoverflow problem
if (allocatedInstance != nil) {
instances[key] = allocatedInstance;
}
instance = [allocatedInstance init];
//Following code may be overly cautious
if (instance != allocatedInstance) {
//Somehow the init method did not return the same instance as the alloc method
if (instance == nil) {
//If init returns nil: immediately remove the instance again
[instances removeObjectForKey:key];
} else {
//Else: put the instance in the dictionary instead of the allocatedInstance
instances[key] = instance;
}
}
}
}
return instance;
}
#import <Foundation/Foundation.h>
#interface SingleTon : NSObject
#property (nonatomic,strong) NSString *name;
+(SingleTon *) theSingleTon;
#end
#import "SingleTon.h"
#implementation SingleTon
+(SingleTon *) theSingleTon{
static SingleTon *theSingleTon = nil;
if (!theSingleTon) {
theSingleTon = [[super allocWithZone:nil] init
];
}
return theSingleTon;
}
+(id)allocWithZone:(struct _NSZone *)zone{
return [self theSingleTon];
}
-(id)init{
self = [super init];
if (self) {
// Set Variables
_name = #"Kiran";
}
return self;
}
#end
Hope above code will help it out.
if you need to create singleton in swift,
class var sharedInstance: MyClass {
struct Singleton {
static let instance = MyClass()
}
return Singleton.instance
}
or
struct Singleton {
static let sharedInstance = MyClass()
}
class var sharedInstance: MyClass {
return Singleton.sharedInstance
}
you can use this way
let sharedClass = LibraryAPI.sharedInstance