Issues with Singleton in objective C - iphone

I am trying to implement a singleton, it is acting as a stub DAO and I need different areas of the application to be able to read and write to it. The first class that uses it can do so without any issue using my sharedSingleton class level constructor, however when I attempt to access this from another class in the exact same way I get a EXC_BAD_ACCESS error and the debug line in the 1st line of the method I am calling on the singleton is never hit.
+(DAOController *) sharedSingleton
{
static DAOController *sharedSingleton;
#synchronized(self)
{
if (!sharedSingleton)
sharedSingleton = [[DAOController alloc] init];
return sharedSingleton;
}
}
-(id) init
{
if (self = [super init])
{
[self initDictionary];
}
return self;
}
I make the exact same call twice both in viewDidLoad
DAOController *daoController = [DAOController sharedSingleton];
self.teams = [daoController getTeamsForPlayer];
But in the 2nd it throws an exception or a EXC_BAD_ACCESS
2011-04-28 18:31:22.403 IScore[5637:207] -[NSKeyValueIvarSetter getTeamsForPlayer]: unrecognized selector sent to instance 0xa707220
2011-04-28 18:31:22.435 IScore[5637:207] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSKeyValueIvarSetter getTeamsForPlayer]: unrecognized selector sent to instance 0xa707220'
Call stack at first throw:
The method simply does
-(NSMutableArray*) getTeamsForPlayer
{
NSMutableArray *teamsForPlayer = [[[NSMutableArray alloc] init] autorelease];
Team *team1 = [self.teams objectForKey:[NSNumber numberWithInt:1]];
[teamsForPlayer addObject:team1];
[team1 release];
return teamsForPlayer;
}
If I change the 2nd instance to non shared I can run the method without issue
DAOController *daoController = [[DAOController alloc]init];
Any assistance would be appreciated. Singleton pattern was taken from last entry on What should my Objective-C singleton look like?

Looks like your singleton has been deallocated and that another instance took its address.
You should check your code to find how this is possible. (you should never retain / release that singleton)
That's why I strongly suggest using Matt Gallagher's cocoawithlove singleton macro that you can download there, which is super easy and concise to use :
SYNTHESIZE_SINGLETON_FOR_CLASS(MyClassName);
It is a perfect singleton implementation, that avoid such issues by deallocating accidently your singleton, which looks like to be your problem. It is based on Apple recommandations, which overrides release, retainCount and such to protect your singleton.

Related

App crashes and Program receives error signal SIGABRT

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: [LeavesCache setDataSource:]: unrecognized selector sent to instance 0x7db1f30
Added Exception breakpoint and found that problem is at this line
pageCache = [[LeavesCache alloc] initWithPageSize:self.bounds.size];
- (void) initialize {
backgroundRendering = NO;
pageCache = [[LeavesCache alloc] initWithPageSize:self.bounds.size];
}
- (id) initWithPageSize:(CGSize)aPageSize
{
if (self = [super init]) {
pageSize = aPageSize;
pageCache = [[NSMutableDictionary alloc] init];
}
return self;
}
- (void) setDataSource:(id<LeavesViewDataSource>)value {
pageCache.dataSource = value;
}
Have no idea how to fix this if some one can help me in this
I'm assuming you're using [this library][1], but it doesn't match up with what you've posted. Because the LeavesCache library on GitHub has no setDataSource method in the code - it's property declared instead. Have you made modifications to the source? Somebody has, because you seem to be setting the pageCache instance variable in one method to a NSMutableDictionary, and in another to a LeavesCache object.
Is there any particular reason why you're using this library? As far as I can tell, it hasn't been updated for three years, and iOS has supported iBooks like page turning interface since iOS 5 natively, using the UIPageViewController class.

Passing parameters with initWithParent methods

method
-(id) initWithParent:(id)parent
{
// do something
}
calling of the above method
theM3u8Parser = [[M3u8Parser alloc] initWithParent:self];
That method works perfect. But now I also need to pass a NSString into the method.
So i changed it to
-(id) initWithParent:(id)parent:(NSString*)str
{
//do something
}
Then i call it like so
theM3u8Parser = [[M3u8Parser alloc] initWithParent:self:aStr];
But now the app crashes with a
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[M3u8Parser initWithParent:]: unrecognized selector sent to instance 0x6a10a50'
Is it not possible to modify this method? If so is there a way of accessing the string which is a member variable of the parent class?
Thanks
-Code
Sure it's possible to modify the method. Try it like this:
- (id)initWithParent:(id)parent andWithString:(NSString *)str;
Then call it like this:
theM3u8Parser = [[M3u8Parser alloc] initWithParent:self andWithString:aStr];

Obj-C: Passing pointers to initialized classes in other classes

I initialized a class in my singleton called DataModel. Now, from my UIViewController, when I click a button, I have a method that is trying to access that class so that I may add an object to one of its dictionaries. My get/set method passes back the pointer to the class from my singleton, but when I am back in my UIViewController, the class passed back doesn't respond to methods. It's like it's just not there. I think it has something to do with the difference in passing pointers around classes or something. I even tried using the copy method to throw a copy back, but no luck.
UIViewController:
ApplicationSingleton *applicationSingleton = [[ApplicationSingleton alloc] init];
DataModel *dataModel = [applicationSingleton getDataModel];
[dataModel retrieveDataCategory:dataCategory];
Singleton:
ApplicationSingleton *m_instance;
DataModel *m_dataModel;
- (id) init {
NSLog(#"ApplicationSingleton.m initialized.");
self = [super init];
if(self != nil) {
if(m_instance != nil) {
return m_instance;
}
NSLog(#"Initializing the application singleton.");
m_instance = self;
m_dataModel = [[DataModel alloc] init];
}
NSLog(#"ApplicationSingleton init method returning.");
return m_instance;
}
-(DataModel *)getDataModel {
DataModel *dataModel_COPY = [m_dataModel copy];
return dataModel_COPY;
}
For the getDataModel method, I also tried this:
-(DataModel *)getDataModel {
return m_dataModel;
}
In my DataModel retrieveDataCategory method, I couldn't get anything to work. I even just tried putting a NSLog in there but it never would come onto the console.
Any ideas?
Most likely you are sending messages that get ignored, e.g. they're being sent to objects which don't exist/aren't the one you're looking for, and for some reason aren't crashing. This occurs in the case of messaging nil, or possibly other illegitimate values. Although you seem to expect that the m_ variables will be initialized to 0, this is not good form, and furthermore you are not following a very typical objc pattern for your singletons -- m_dataModel should be an ivar of m_instance, and m_instance should probably be declared static, as you probably don't want it accessed from other files directly. In addition, the most likely source of your bug is somehow the -init method, which should never be called on a singleton -- instead do something like this:
+ (ApplicationSingleton *)sharedInstance {
static ApplicationSingleton *instance = nil;
if(!instance) {
instance = [[self alloc] init]; //or whatever custom initializer you would like, furthermore some people just put the initialization code here and leave -init empty
}
return instance;
}
the code you have now leaks because you allocate an object (self) and don't release it before returning a potentially different instance (the shared one if one already exists), such that the newly allocated one is typically lost.

Apple Singleton example query?

I am a little confused by this snippet of code (presented in the CocoaFundamentals guide) that overrides some of the methods when creating a singleton instance.
static id sharedReactor = nil;
+(id)sharedInstance {
if(sharedReactor == nil) sharedReactor = [[super allocWithZone:NULL] init];
return sharedReactor;
}
.
+(id)allocWithZone:(NSZone *)zone {
return[[self sharedInstance] retain];
}
-(id)retain {
return self;
}
In the code where the singleton instance is created the +sharedInstance method calls [super allocWithZone:NILL] from the superclass (which in my case is NSObject) The allocWithZone above is only called if you attempt to use it to create a new singleton.
The bit I am confused about is the use of retain, especially seeing as retain is also overridden to return self. Can anyone explain this, could it not be written:
+(id)allocWithZone:(NSZone *)zone {
return [self sharedInstance];
}
-(id)retain {
return self;
}
EDIT_001:
Based on comments and reading various posts on the web I have decided to go with the following (see below) I have chosen to go for a shared singleton approach where if needed I would have the option of creating a second or third instance. Also at this stage as I am only using the singleton for the model portion of MVC for a simple iPhone app I have decided to leave thread safety out. I am aware its important and as I get more familiar with iPhone programming I will likely use +initialize instead (keeping in mind the subclass issue where it can be called twice) Also I have added a dealloc, firstly to log a message should the singleton be released, but also to clean things up properly should the singleton be no longer required.
#interface SharedManager : NSObject
+(id)sharedInstance;
#end
#implementation SharedManager
static id myInstance = nil;
+(id)sharedInstance {
if(myInstance == nil) {
myInstance = [[self alloc] init];
}
return myInstance;
}
-(void)dealloc {
NSLog(#"_deal: %#", [self class]);
[super dealloc];
myInstance = nil;
}
#end
In testing I found that I had a set the static variable to nil in the dealloc or it maintained its pointer to the original object. I was initially a little confused by this as I was expecting the scope of the static to be the instance, I guess its the class instead, which makes sense.
cheers gary
First, don't use this code. There is almost never a reason to do all this for a simple singleton. Apple is demonstrating a "Forced Singleton," in that it is impossible to create two of them. It is very rare to really need this. You can almost always use the "shared singleton" approach used by most of the Cocoa objects that have a singleton constructor.
Here's my preferred way of implementing shared singleton:
+ (MYManager *)sharedManager
{
static MYManager *sharedManager = nil;
if (sharedManager == nil)
{
sharedManager = [[self alloc] init];
}
return sharedManager;
}
That's it. No other code is required. Callers who use +sharedManager will get the shared instance. Callers who call +alloc can create unique instances if they really want to. This is how such famous "singletons" as NSNotificationCenter work. If you really want your own private notification center, there is no reason the class should forbid it. This approach has the following advantages:
Less code.
More flexible in cases where a non-shared instance is useful.
Most importantly: the code does what it says it does. A caller who thinks he's making a unique instance with +alloc doesn't encounter surprising "spooky action at a distance" behavior that requires him to know an internal implementation detail of the object.
If you really need a forced singleton because the object in question maps to a unique resource that cannot be shared (and it's really rare to encounter such a situation), then you still shouldn't use +alloc trickery to enforce it. This just masks a programming error of trying to create a new instance. Instead, you should catch the programming error this way:
+ (MYManager *)sharedManager
{
static MYManager *sharedManager = nil;
if (sharedManager == nil)
{
sharedManager = [[self alloc] initSharedManager];
}
return sharedManager;
}
- (id)init
{
NSAssert(NO, #"Attempting to instantiate new instance. Use +sharedManager.");
return nil;
}
// Private method. Obviously don't put this in your .h
- (id)initSharedManager
{
self = [super init];
....
return self;
}
There is a good example of different singleton methods with comments here on SO:
What does your Objective-C singleton look like?
If it helps, the example has a different approach to allocWithZone: which returns nil.

Initialize a class only once

I have a class that contains a few instance methods which need to be called from another class. I know how to do that -
TimeFormatter *myTimeFormatter = [[TimeFormatter alloc] init];
[myTimeFormatter formatTime:time];
However, I don't want to have to alloc and init TimeFormatter every time I need to call one of its methods. (I need to call TimeFormatter's methods from various methods in another class).
I tried putting
TimeFormatter *myTimeFormatter = [[TimeFormatter alloc] init];
"by itself", or not in any blocks, but when I compile, I get an "initializer element is not constant" error.
Any input is greatly appreciated!
You can use the singleton pattern. You can read more about it here.
Specifically, you'd do something like:
static TimeFormatter* gSharedTimeFormatter = nil;
#implementation TimeFormatter
+ (TimeFormatter*)sharedTimeFormatter {
if (!gSharedTimeFormatter) {
#synchronized(self) {
if (!gSharedTimeFormatter) {
gSharedTimeFormatter = [[TimeFormatter alloc] init];
}
}
}
return gSharedTimeFormatter;
}
...
#end
Notice that we check if the variable is null, and if it is, we take a lock, and check again. This way, we incur the locking cost only on the allocation path, which happens only once in the program. This pattern is known as double-checked locking.
However, I don't want to have to alloc and init TimeFormatter every time I need to call one of its methods. (I need to call TimeFormatter's methods from various methods in another class).
I think it's worth clarifying some OOP terminology here.
The reason you need to alloc and init TimeFormatter is because your methods are instance methods. Because they're instance methods, you need an instance, and that's what alloc and init provide. Then you call your methods on (send messages to) the instance ([myTimeFormatter formatTimeString:…]).
The advantage of allowing instances is that you can keep state and settings in each instance, in instance variables, and make the latter into publicly-visible properties. Then you can deliberately have multiple instances, each having its own settings configured by whatever's using that instance.
If you don't need that functionality, you don't need to make these instance methods. You can make them class methods or even C functions, and then you don't need a TimeFormatter instance. With class methods, you send messages directly to the class ([TimeFormatter formatTimeString:…]).
And if you do want settings shared among all instances (and you don't have any state to keep), then you're right that you can just have one instance—a singleton.
The reason for that parenthesis is that shared state is bad, especially if two threads may use the time formatter concurrently. (For that matter, you could say that about settings, too. What if one thread wants seconds and the other doesn't? What if one wants 24-hour and the other wants 12-hour?) Better to have each thread use its own time formatter, so that they don't get tripped up by each other's state.
(BTW, if TimeFormatter is the actual name of your class: You are aware of NSDateFormatter, right? It does let you only format/parse the time.)
Here's a detail example of a sharedMethod. Credit goes here
#implementation SearchData
#synthesize searchDict;
#synthesize searchArray;
- (id)init {
if (self = [super init]) {
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *finalPath = [path stringByAppendingPathComponent:#"searches.plist"];
searchDict = [[NSDictionary alloc] initWithContentsOfFile:finalPath];
searchArray = [[searchDict allKeys] retain];
}
return self;
}
- (void)dealloc {
[searchDict release];
[searchArray release];
[super dealloc];
}
static SearchData *sharedSingleton = NULL;
+ (SearchData *)sharedSearchData {
#synchronized(self) {
if (sharedSingleton == NULL)
sharedSingleton = [[self alloc] init];
}
return(sharedSingleton);
}
#end
A very nice, and easy, way to setup a Singleton is to use Matt Gallager's SYNTHESIZE_SINGLETON_FOR_CLASS.
It sounds like you want to make TimeFormatter a singleton, where only one instance can be created. Objective-C doesn't make this super easy, but basically you can expose a static method that returns a pointer to TimeFormatter. This pointer will be allocated and initialized the first time in, and every time after that same pointer can be used. This question has some examples of creating a singleton in Objective-C.
You are trying to declare your variable outside the class? If to do it the way you want to do it you gotta declare it as static so
static TimeFormatter *myFormatter=...
From the name of the class though i dont see why you would wnat to keep one instance of your class... you can also do this with a singleton as described above, that is if you want to keep one instance of your class for the app as a whole.