Issue with two objects that create each other, infinite loop - objective-c

I have two objects, DNLocations, that have arrays of other locations inside of them. The idea i'm trying to get across is that you can go from one location to another, and back to the previous one. Unfortunately, when i create the locations like this, they keep creating each other resulting in an infinite loop. I'm not sure what to do here. I've seen circular references but this seems like something else.
+ (DNLocation *) aCell {
static dispatch_once_t onceToken;
static DNLocation *instance = nil;
dispatch_once(&onceToken, ^{
instance = [DNLocation locationWithName:#"A Cell" andActions:[NSArray arrayWithObjects: [DNAction doNothingAction], nil] andLocations:[NSArray arrayWithObjects:[DNLocation aWhiteRoom], nil]];
});
return instance;
}
+ (DNLocation *) aWhiteRoom {
static dispatch_once_t onceToken;
static DNLocation *instance = nil;
dispatch_once(&onceToken, ^{
instance = [DNLocation locationWithName:#"A White Room" andActions:nil andLocations:[NSArray arrayWithObjects:[DNLocation aCell], nil]];
});
[instance setColor:[UIColor DNWhiteColor]];
[instance setFontColor:[UIColor DNBlackColor]];
return instance;
}
+ (DNLocation *) locationWithName:(NSString *) name {
return [[DNLocation alloc] initWithName:name];
}
These methods are called upon load of the app, setting up all of the possible locations to go to.
I'd rather not have to instantiate them and then add the locations to themselves, but if that is the only way then i'll do it.

Related

Bad Access Code 1 when using a Singleton

I need some help.
I'm using this singleton pattern within an iOS application I'm developing:
.h file
#import <Foundation/Foundation.h>
#class Item;
#interface ItemManager : NSObject
- (id)init;
+ (ItemManager *)sharedInstance;
- (int)ratingFromObjectName:(NSString *)objectName;
#property(nonatomic,strong) NSArray *itemArray;
#end
.m file
static ItemManager *sharedInstance = nil;
+ (ItemManager *)sharedInstance
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[ItemManager alloc] init];
});
return sharedInstance;
}
- (int)ratingFromObjectName:(NSString *)objectName {
for (int i = 0; i < itemArray.count; i++) {
if ([[[itemArray objectAtIndex:i] itemName] isEqualToString:objectName]) { //This is the line that throws bad access code 1
NSLog(#"Found: %# Returned: %d", [[itemArray objectAtIndex:i] ratingAverage],
[[[itemArray objectAtIndex:i] ratingAverage] intValue]);
return [[[itemArray objectAtIndex:i] ratingAverage] intValue];
}
}
return 0;
}
I get bad access when I use this in another class:
int rating = [[ItemManager sharedInstance] ratingFromObjectName:bla];
The bla object being sent is a NSString that is definitely working, it is 100% not the issue, as I have tested this. Removing the sharedInstance method and creating an array every time seems to work, however my attempt for this singleton is to avoid that, any suggestions would be greatly appreciated.
Please note that I have commented on the line returning the error.
Regards, WA
You need to work out which line of code is throwing the bad access. Is it the sharedInstance method or ratingFromObjectName:. I would first change the calling code to
ItemManager *manager = [ItemManager sharedInstance];
int rating = [manager ratingFromObjectName:bla];
As that will help with isolating the problem.
Secondly, I would also consider not using the Singleton pattern unless really necessary is iOS apps. It's been my experience that it is often overused (and in the Java world), and whilst convenient, can make writing unit tests more complicated.

Best singleton pattern for thread safe object [duplicate]

This question already has answers here:
What should my Objective-C singleton look like? [closed]
(26 answers)
Closed 9 years ago.
Whats the best pattern for singleton? I frequently use
+ (SomeManager *)shared
{
static SomeManager * _SomeManager = nil;
if (_SomeManager) {
return _SomeManager;
}
_SomeManager = [[SomeManager alloc] init];
return _SomeManager;
}
Is this thread safe? If not, hot to make it safe?
Using an example from
Create singleton using GCD's dispatch_once in Objective C
+ (id)sharedInstance
{
static dispatch_once_t once;
static id sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
Clear and simple. Google better next time.
I prefer to use the GCD dispatch_once method...
+ (id) sharedSomethingManager
{
static dispatch_once_t onceQueue;
static SomethingkManager *somethingManager = nil;
dispatch_once(&onceQueue, ^{somethingManager = [[self alloc] init]; });
return somethingManager;
}

Initializing NSImage(s) as static objects

I have a custom control in OSX with a drawing routine. Every instance of this control uses the same images.
I wonder if it's a good idea to instantiate these images as static objects available for all the instances created by the class.
In case that was a good idea, how can I implement the image loader in a cleaver way?
I thought to add to my class something like
static NSImage *imageone;
static NSImage *imagetwo;
static NSImage *imagethree;
But I'm not sure about the better way to initialize the images... maybe a singleton function like this?
+ (void)setupSharedImages {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
imageone = [NSimage imageNamed:#"...."];
imagetwo = [NSimage imageNamed:#"...."];
image three = [NSimage imageNamed:#"...."];
});
}
You can setup you images in + (void)initialize method. This method is called once when class is loaded and it also handles synchronization.
As an option, you may think of incapsulating images into "storage" singleton class.
#interface ImageStorage : NSObject
+ (ImageStorage *)sharedStorage;
- (NSImage *)imageForKey:(NSString *)key;
#end
#implementation ImageStorage {
NSDictionary *_images;
}
+ (ImageStorage *)sharedStorage
{
static dispatch_once_t onceToken;
static ImageStorage *sharedStorage;
dispatch_once(&onceToken, ^{
sharedStorage = [[ImageStorage alloc] init];
_images = [[NSDictionary dictionaryWithObjectsAndKeys:image1, key1, image2, key2, nil] retain];
});
return sharedStorage;
}
- (NSImage *)imageForKey:(NSString *)key
{
return [_images objectForKey:key];
}
#end
You could always lazy load them.
- (NSImage *)imageOne {
static NSImage *imageone;
if(imageone == nil)
imageone = [NSImage imageNamed:#"..."];
return imageone;
}
Edit:
Just wanted to clarify, do this for each image you need then in your draw method call
[self imageOne] etc...

Basic IOS OOP - structure and implementation

I am creating a basic guessing game in iOS for my kids, and I think there are some fundamental gaps in my understanding of how I should be creating and releasing objects throughout the lifecycle of the app. I have been reading up on retain and release cycles but I think my issue is more to do with the fundamental architecture of the app and how I may be poorly trying to instantiate and then kill a few key objects of the app.
The problem centers around two specific classes.
I have a game class, which I have designed to hold all the information that the game requires to run. When it is init-ed, it holds all instance variables that point to arrays that hold strings such as the various clues, etc. It's basically a container for all the data that the game requires.
I have a game view controller, that creates and an instance of the game class and queries it so as to present on screen the various elements contained with the game object.
This works perfectly the fine. When the user starts a new game, a new instance of the game class is allocated and init-ed and away they go.
The issue comes in when I come to generate a new game. This happens a number of ways. Either The user finishes the game and starts another one or the user quits the current game and then starts a new one.
In my thinking, I would just release the game object and alloc and init a new one. However, I notice running on the device and looking through the profiler, that the game object isn't released at all.It's still, there and each instantiation of the game creates a new game object with the old one still sitting there with no pointers to it.
Fiddling around with the code, I noticed that I did not implement a dealloc method in the Game class...but when I try to do that, the app crashes, I suspect because I am trying to release a previously released object.
Ideally what I am trying to do is get rid of the old Game object, or replace the old one (overwrite) with a new one each time a new game is started.
However, is this approach wrong? Should I be doing it a completely different way? Such as only ever creating a single instance of the game class and rewriting a method inside that class so as to generate a new set of clues, etc everytime a new game starts and the GameViewController tells it to?
Is there a 'best practice' way to do this?
So you've got an idea of what I am doing, code is below for the GameViewController, where an instance of the Game class is created:
#import "GameViewController.h"
#implementation GameViewController
#synthesize game = _game;
-(void)startNewGameOfLevel:(NSInteger)level
{
if(!_game)
{
Game *g = [[Game alloc]initGamewithLevel:level];
[self setGame:g];
[g release]; g = nil;
}
[self set_currentlevel:[_game _currentLevel]];
// set up popover to show the rounds goal letter
[self setUpPopOver];
}
-(void)quitTheCurrentGameAndStartNewGame
{
[_game release]; _game = nil;
[self clearGamePlayingField];
animationStepIndex = 0;
[self startNewGameOfLevel: _currentlevel];
}
Game class (abridged) with the designated initializer of the Game class:
#import "Game.h"
#implementation Game
#synthesize arrayOfLowerCaseLetters = _arrayOfLowerCaseLetters;
#synthesize arrayOfPhrases= _arrayOfPhrases;
#synthesize goalLetter = _goalLetter;
#synthesize goalPhrase = _goalPhrase;
#synthesize gameLetterPool = _gameLetterPool;
#synthesize _indexForGoalLetter, _numberOfLevelsInGame, _currentLevel, _numberOfWhackHoles, _numberOfLettersInGameLetterPool;
-(id)initGamewithLevel:(NSInteger)level
{
[super init];
//create an array of lower case letters. These will
//contain the full alphabet of all possible letters
NSArray *arrayOfLCLetters = [[NSArray alloc] initWithObjects:#"a", #"b", #"c", #"d",#"e", #"f", #"g", #"h", #"i", #"j", #"k", #"l", #"m", #"n", #"o", #"p", #"qu", #"r", #"s", #"t", #"u", #"v", #"w", #"x",#"y", #"z",#"ch", #"sh", #"th", nil];
[self setArrayOfLowerCaseLetters: arrayOfLCLetters];
[arrayOfLCLetters release];arrayOfLCLetters = nil;
//create an array of phrases.
// These must correspond with each of the letters. e.g. a = apple.
NSArray *phrases= [[NSArray alloc ] initWithObjects:
#"apple",
#"butterfly",
#"cat",
#"dog",
#"egg",
#"frog",
#"ghost",
#"horse",
#"igloo",
#"jam",
#"kite",
#"leaf",
#"moon",
#"nut",
#"orange",
#"pig",
#"queen",
#"rabbit",
#"snake",
#"tree",
#"umbrella",
#"van",
#"water",
#"x-ray",
#"yak",
#"Zebra",
#"chair",
#"shoes",
#"thumb",
nil];
[self setArrayOfPhrases:phrases];
[phrases release]; phrases = nil;
//choose a random number to be the index reference for
// each goal letter and goal phrase.
[self set_indexForGoalLetter:(arc4random()%[_arrayOfLowerCaseLetters count])];
NSLog(#"index for goal letter is:, %i", _indexForGoalLetter);
//set Goal letter and goal phrase
[self setGoalLetter: [_arrayOfLowerCaseLetters objectAtIndex: _indexForGoalLetter]];
[self setGoalPhrase: [_arrayOfPhrases objectAtIndex:_indexForGoalLetter ]];
//set current level
[self set_currentLevel: level];
//[self set_currentLevel: 2];
//set number of whackholes by level
[self set_numberOfWhackHoles: [self numberOfWhackHolesByLevel:_currentLevel]];
//generate size of Letter pool by level
[self set_numberOfLettersInGameLetterPool:[self numberOfLettersInLetterPoolbyLevel:_currentLevel]];
////////////////////////////
/// Game letter pool
///////////////////////////
//set up array ton hold the pool of letters
NSMutableArray *gp = [[NSMutableArray alloc] initWithCapacity:_numberOfLettersInGameLetterPool];
[self setGameLetterPool: gp];
[gp release];gp = nil;
//add the goal letter to this pool
[_gameLetterPool addObject:_goalLetter];
int i = 1;
while (i < _numberOfLettersInGameLetterPool) {
NSString *letter = [_arrayOfLowerCaseLetters objectAtIndex:(arc4random()%[_arrayOfLowerCaseLetters count])];
if ([_gameLetterPool containsObject:letter] == false)
{
[_gameLetterPool addObject:letter];
i++;
}
}
NSLog(#"********** Game created ***************");
NSLog(#"pool of letters is: %#", [_gameLetterPool description]);
NSLog(#"****************************************");
NSLog(#"current goal letter is: %#", _goalLetter);
NSLog(#"****************************************");
NSLog(#"current goal phrase is: %#", _goalPhrase);
NSLog(#"****************************************");
return self;
}
-(void)dealloc
{
[super dealloc];
[_arrayOfLowerCaseLetters release]; _arrayOfLowerCaseLetters = nil;
[_arrayOfPhrases release]; _arrayOfPhrases = nil;
[_goalLetter release];_goalLetter = nil;
[_goalPhrase release]; _goalPhrase = nil;
[_gameLetterPool release];_gameLetterPool = nil;
}
The number one problem is that [super dealloc] must be the absolute last thing you do in -dealloc. This is because it is the dealloc method in NSObject that actually frees the memory, so by the time you get back to it, your instance variable pointers may already be garbage.
Other issues:
In init, do self = [super init]; The super object is allowed to return a different self pointer on init.
startNewGameOfLevel: and quitTheCurrentGameAndStartNewGame should use the property, not the bare instance variable.
-(void)startNewGameOfLevel:(NSInteger)level
{
if(![self game])
{
Game *g = [[Game alloc]initGamewithLevel:level];
[self setGame:g];
[g release]; g = nil;// g = nil, not necessary when it's about to go out of scope
}
[self set_currentlevel:[[self game] _currentLevel]]; // don't use _ to start methods - Apple reserves this convention
// set up popover to show the rounds goal letter
[self setUpPopOver];
}
-(void)quitTheCurrentGameAndStartNewGame
{
[self setGame: nil];
[self clearGamePlayingField];
animationStepIndex = 0;
[self startNewGameOfLevel: _currentlevel];
}
There are probably other issues in the body of your code - make sure you build with static analysis enables - it will catch many of them.

iOS Singleton Variables Not Keeping Their Values

So I'm still kind of new to Objective-C, and this was my first app that I'm now updating. The idea is this: The whole app is basically various lists of stuff. It asks the API for 15 posts, shows those with a Load More button. Click Load More, it loads 15 more, etc. The API that it loads these from has a token system with a timeout built in. Too long between requests, and you have to get a new token. So I want to have a singleton to use anywhere in my app so I can just do [APIMachine getToken] and behind the scenes, it checks if the time since the last request was too long (or this is the first request), if so, gets a new token, otherwise returns the one we already have. I'm following the singleton pattern I've found in so many places, but every time the Load More button uses [APIMachine getToken]it gets either nothing or something completely random. I had it print this stuff in the logs, and one time I even got a UITableViewCell as my token. Looks like variables are being overwritten somehow. But I really can't figure it out.
So here it is:
static PoorAPI2 *_instance;
#implementation PoorAPI2
#synthesize apiToken, timeOpened, tokenTTL;
+ (PoorAPI2*)sharedAPI
{
#synchronized(self) {
if (_instance == nil) {
_instance = [[super allocWithZone:NULL] init];
}
}
return _instance;
}
-(NSString *)API_open{
//boring code to get api token redacted
if ([doneness isEqualToString:#"success"]) {
NSDictionary *data = [json objectForKey:#"data"];
apiToken = [data objectForKey:#"api_token"];
tokenTTL = [data objectForKey:#"ttl"];
timeOpened = [NSDate date];
}else{
NSLog(#"FFFFFFFUUUUUUUUUUUU this error should be handled better.");
}
return apiToken;
}
-(BOOL)isConnectionOpen{
return ([timeOpened timeIntervalSinceNow] > tokenTTL);
}
-(NSString *)getToken{
if([self isConnectionOpen]){
return apiToken;
}else{
return [_instance API_open];
}
}
-(id)init{
if(self = [super init]){
apiToken = [[NSString alloc] initWithString:#""];
timeOpened = [[NSDate alloc] initWithTimeIntervalSinceNow:0];
tokenTTL = 0;
}
return self;
}
+ (id)allocWithZone:(NSZone *)zone
{
return [[self sharedAPI]retain];
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
- (id)retain
{
return self;
}
- (unsigned)retainCount
{
return NSUIntegerMax; //denotes an object that cannot be released
}
- (void)release
{
//do nothing
}
- (id)autorelease
{
return self;
}
#end
I can only hope I'm doing something seriously foolish and this will be a hilarious point-and-laugh-at-that-guy thread. Then at least my app will work.
In API_open, you store three objects in instance variables, but they're not objects you own, so they'll probably be gone by the time you need them and replaced by something unpredictable. You need to retain them or use proper setters.
You problem is:
static PoorAPI2 *_instance;
C, and by inheritance Objective-C, do not initialize variables. Just change to:
static PoorAPI2 *_instance = nil;
Also I am of the school that adding extra code to try to prevent the singleton from being used as a single is a total waste of time, and only give you more code with more possibilities for bugs.
So if I was you then I would remove every method from +[PoorApi2 allocWithZone:] and down. Objective-C is a dynamic language and if a client wanted to instantiate a second instance of your singleton then it would be able to do so despite all your wasted extra lines of code. At the most I would add a log like this:
-(id)init{
if (_instance) NSLog(#"WARNING: PoorAPI2 already has a shared instance.");
if(self = [super init]){
apiToken = [[NSString alloc] initWithString:#""];
timeOpened = [[NSDate alloc] initWithTimeIntervalSinceNow:0];
tokenTTL = 0;
}
return self;
}
Creating a second instance of a singleton is a programming error and should be caught in development. Not a problem you should add extra lines of code to hide.