RWGameData.h
#import <Foundation/Foundation.h>
#class RWGameData;
#protocol RWGameStateProtocol <NSObject>
-(void)StateUpdateForGameData:(RWGameData*)data;
#end
#interface RWGameData : NSObject <NSCoding>
#property (weak) id<RWGameStateProtocol> delegate;
#property (assign, nonatomic) long regularBubbleCount;
#property (assign, nonatomic) long premiumBubbleCount;
#property (assign, nonatomic) long megaBubbleUpgradeTier;
#property (assign, nonatomic) long bubbleFactoryUpgradeTier;
#property (assign, nonatomic) long bubblersUpgradeTier;
#property (assign, nonatomic) long mysteryBubbleUpgradeTier;
#property (assign, nonatomic) long bubbleBankUpgradeTier;
#property (assign, nonatomic) int megaBubblePopValue;
#property (assign, nonatomic) int bubbleFactoryTickValue;
#property (assign, nonatomic) long bubbleBankCapacity;
#property (assign, nonatomic) int collectionBallsQuantity;
#property (assign, nonatomic) int collectionGlowsticksQuantity;
#property (assign, nonatomic) int collectionFlowersQuantity;
#property (assign, nonatomic) int collectionStuffedAnimalsQuantity;
#property (assign, nonatomic) int collectionEasterEggsQuantity;
#property (assign, nonatomic) int currentXP;
#property (assign, nonatomic) int targetXP;
#property (assign, nonatomic) int level;
#property (assign, nonatomic) BOOL dataIsInitialized;
+(instancetype)sharedGameData;
-(void)reset;
-(void)save;
-(void)timerSetup;
-(void)timerCalled;
#end
RWGameData.m
#import "RWGameData.h"
#implementation RWGameData
static NSString* const SSGameDataRegularBubbleCountKey = #"regularBubbleCount";
static NSString* const SSGameDataPremiumBubbleCountKey = #"premiumBubbleCount";
static NSString* const SSGameDataMegaBubbleUpgradeTierKey = #"megaBubbleUpgradeTier";
static NSString* const SSGameDataBubbleFactoryUpgradeTierKey = #"bubbleFactoryUpgradeTier";
static NSString* const SSGameDataBubblersUpgradeTierKey = #"bubblersUpgradeTier";
static NSString* const SSGameDataMysteryBubbleUpgradeTierKey = #"mysteryBubbleUpgradeTier";
static NSString* const SSGameDataBubbleBankUpgradeTierKey = #"bubbleBankUpgradeTier";
static NSString* const SSGameDataMegaBubblePopValueKey = #"megaBubblePopValueKey";
static NSString* const SSGameDataBubbleFactoryTickValueKey = #"bubbleFactoryTickValueKey";
static NSString* const SSGameDataBubbleBankCapacityKey = #"bubbleBankCapacityKey";
static NSString* const SSGameDataCollectionBallsQuantityKey = #"collectionBallsQuantityKey";
static NSString* const SSGameDataCollectionGlowsticksQuantityKey = #"collectionGlowsticksQuantityKey";
static NSString* const SSGameDataCollectionFlowersQuantityKey = #"collectionFlowersQuantityKey";
static NSString* const SSGameDataCollectionStuffedAnimalsQuantityKey = #"collectionStuffedAnimalsQuantityKey";
static NSString* const SSGameDataCollectionEasterEggsQuantityKey = #"collectionEasterEggsQuantityKey";
/*static NSString* const SSGameDataCollectionBallsModifierKey = #"collectionBallsModifierKey";
static NSString* const SSGameDataCollectionGlowsticksModifierKey = #"collectionGlowsticksModifierKey";
static NSString* const SSGameCollectionFlowersModifierKey = #"collectionFlowersModifierKey";
static NSString* const SSGameCollectionStuffedAnimalsModifierKey = #"collectionStuffedAnimalsModifierKey";
static NSString* const SSGameCollectionEasterEggsModifierKey = #"collectionEasterEggsModifierKey";*/
static NSString* const SSGameDataCurrentXPKey = #"currentXPKey";
static NSString* const SSGameDataTargetXPKey = #"targetXPKey";
static NSString* const SSGameDataLevelKey = #"levelKey";
static NSString* const SSGameDataIsInitializedKey = #"dataIsInitializedKey";
+ (instancetype)sharedGameData {
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [self loadInstance];
});
return sharedInstance;
}
-(void)reset {
self.regularBubbleCount = 0;
self.premiumBubbleCount = 0;
self.megaBubbleUpgradeTier = 0;
self.bubbleFactoryUpgradeTier = 0;
self.bubblersUpgradeTier = 0;
self.mysteryBubbleUpgradeTier = 0;
self.bubbleBankUpgradeTier = 0;
self.megaBubblePopValue = 1;
self.bubbleFactoryTickValue = 1;
self.bubbleBankCapacity = 500;
self.collectionBallsQuantity = 0;
self.collectionGlowsticksQuantity = 0;
self.collectionFlowersQuantity = 0;
self.collectionStuffedAnimalsQuantity = 0;
self.collectionEasterEggsQuantity = 0;
self.currentXP = 0;
self.targetXP = 83;
self.level = 1;
self.dataIsInitialized = true;
}
- (void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeDouble:self.regularBubbleCount forKey: SSGameDataRegularBubbleCountKey];
[encoder encodeDouble:self.premiumBubbleCount forKey: SSGameDataPremiumBubbleCountKey];
[encoder encodeDouble:self.megaBubbleUpgradeTier forKey: SSGameDataMegaBubbleUpgradeTierKey];
[encoder encodeDouble:self.bubbleFactoryUpgradeTier forKey: SSGameDataBubbleFactoryUpgradeTierKey];
[encoder encodeDouble:self.bubblersUpgradeTier forKey: SSGameDataBubblersUpgradeTierKey];
[encoder encodeDouble:self.mysteryBubbleUpgradeTier forKey: SSGameDataMysteryBubbleUpgradeTierKey];
[encoder encodeDouble:self.bubbleBankUpgradeTier forKey: SSGameDataBubbleBankUpgradeTierKey];
[encoder encodeDouble:self.megaBubblePopValue forKey: SSGameDataMegaBubblePopValueKey];
[encoder encodeDouble:self.bubbleFactoryTickValue forKey: SSGameDataBubbleFactoryTickValueKey];
[encoder encodeDouble:self.bubbleBankCapacity forKey: SSGameDataBubbleBankCapacityKey];
[encoder encodeDouble:self.collectionBallsQuantity forKey: SSGameDataCollectionBallsQuantityKey];
[encoder encodeDouble:self.collectionGlowsticksQuantity forKey: SSGameDataCollectionGlowsticksQuantityKey];
[encoder encodeDouble:self.collectionFlowersQuantity forKey: SSGameDataCollectionFlowersQuantityKey];
[encoder encodeDouble:self.collectionStuffedAnimalsQuantity forKey: SSGameDataCollectionStuffedAnimalsQuantityKey];
[encoder encodeDouble:self.collectionEasterEggsQuantity forKey: SSGameDataCollectionEasterEggsQuantityKey];
[encoder encodeDouble:self.currentXP forKey: SSGameDataCurrentXPKey];
[encoder encodeDouble:self.targetXP forKey: SSGameDataTargetXPKey];
[encoder encodeDouble:self.level forKey:SSGameDataLevelKey];
[encoder encodeBool:self.dataIsInitialized forKey: SSGameDataIsInitializedKey];
}
- (instancetype)initWithCoder:(NSCoder *)decoder
{
self = [self init];
if (self) {
_regularBubbleCount = [decoder decodeDoubleForKey: SSGameDataRegularBubbleCountKey];
_premiumBubbleCount = [decoder decodeDoubleForKey: SSGameDataPremiumBubbleCountKey];
_megaBubbleUpgradeTier = [decoder decodeDoubleForKey: SSGameDataMegaBubbleUpgradeTierKey];
_bubbleFactoryUpgradeTier = [decoder decodeDoubleForKey: SSGameDataBubbleFactoryUpgradeTierKey];
_bubblersUpgradeTier = [decoder decodeDoubleForKey: SSGameDataBubblersUpgradeTierKey];
_mysteryBubbleUpgradeTier = [decoder decodeDoubleForKey: SSGameDataMysteryBubbleUpgradeTierKey];
_bubbleBankUpgradeTier = [decoder decodeDoubleForKey: SSGameDataBubbleBankUpgradeTierKey];
_megaBubblePopValue = [decoder decodeDoubleForKey: SSGameDataMegaBubblePopValueKey];
_bubbleFactoryTickValue = [decoder decodeDoubleForKey: SSGameDataBubbleFactoryTickValueKey];
_bubbleBankCapacity = [decoder decodeDoubleForKey: SSGameDataBubbleBankCapacityKey];
_collectionBallsQuantity = [decoder decodeDoubleForKey: SSGameDataCollectionBallsQuantityKey];
_collectionGlowsticksQuantity = [decoder decodeDoubleForKey: SSGameDataCollectionGlowsticksQuantityKey];
_collectionFlowersQuantity = [decoder decodeDoubleForKey: SSGameDataCollectionFlowersQuantityKey];
_collectionStuffedAnimalsQuantity = [decoder decodeDoubleForKey: SSGameDataCollectionStuffedAnimalsQuantityKey];
_collectionEasterEggsQuantity = [decoder decodeDoubleForKey: SSGameDataCollectionEasterEggsQuantityKey];
_currentXP = [decoder decodeDoubleForKey: SSGameDataCurrentXPKey];
_targetXP = [decoder decodeDoubleForKey: SSGameDataTargetXPKey];
_level = [decoder decodeDoubleForKey: SSGameDataLevelKey];
_dataIsInitialized = [decoder decodeBoolForKey: SSGameDataIsInitializedKey];
}
return self;
}
+(NSString*)filePath
{
static NSString* filePath = nil;
if (!filePath) {
filePath =
[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]
stringByAppendingPathComponent:#"gamedata"];
}
return filePath;
}
+(instancetype)loadInstance
{
NSData* decodedData = [NSData dataWithContentsOfFile: [RWGameData filePath]];
if (decodedData) {
RWGameData* gameData = [NSKeyedUnarchiver unarchiveObjectWithData:decodedData];
return gameData;
}
return [[RWGameData alloc] init];
}
-(void)save
{
NSData* encodedData = [NSKeyedArchiver archivedDataWithRootObject: self];
[encodedData writeToFile:[RWGameData filePath] atomically:YES];
}
- (void)timerSetup { // to be called from delegate didFinishLaunching….
NSTimer *timer;
timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(timerCalled) userInfo:nil repeats:YES];
}
-(void)timerCalled
{
//NSLog(#"Timer Called");]
if ([RWGameData sharedGameData].bubbleFactoryUpgradeTier > 0) {
if ([RWGameData sharedGameData].regularBubbleCount < [RWGameData sharedGameData].bubbleBankCapacity) {
[RWGameData sharedGameData].regularBubbleCount += [RWGameData sharedGameData].bubbleFactoryTickValue;
[[RWGameData sharedGameData] save];
} else {
NSLog(#"Capacity Reached! Capacity: %li", [RWGameData sharedGameData].bubbleBankCapacity);
}
[self.delegate StateUpdateForGameData:self];
} NSLog(#"Regular Bubble Count: %li", [RWGameData sharedGameData].regularBubbleCount);
}
#end
PrimaryViewController.h
#import <UIKit/UIKit.h>
#import "RWGameData.h"
#interface PrimaryViewController : UIViewController <RWGameStateProtocol>
#property (strong, nonatomic) IBOutlet UILabel *regularBubLabel;
#end
I would like to be able to change the value of regularBubLabel from within the timerCalled method. Thank you for your time.
Included the entirety of my RWGameData class as it was requested. Thanks.
AppDelegate.h
#import <UIKit/UIKit.h>
#import "RWGameData.h"
#import "PrimaryViewController.h"
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong,nonatomic) RWGameData *gameData;
#end
Then see +(instancetype)loadInstance of #RWGameData.m
If you can provide more details of what you are trying to achieve.
If I understand correctly you want to know which tab is active
all you have to do is get tab.selectedIndex property which will return back to you int representing the index of activTabView then you can do anything with it such as change the Text of the selected index
Hope this help.
From your code I can see that your PrimaryViewController is confirming the protocol for RWGameData i.e
#interface PrimaryViewController : UIViewController <RWGameStateProtocol>
so, set the delegate of RWGameData to PrimaryViewController Object, then implement this delegate method in PrimaryViewController.m like
-(void)StateUpdateForGameData:(RWGameData*)data
{
//now update label
self.regularBubLabel.text = #"asdasd";
}
Edit:
In PrimaryViewController.m viewDidLoad method add this line
[RWGameData sharedGameData].delegate = self;
timercalled method should be like
-(void)timerCalled
{
//NSLog(#"Timer Called");]
if ([RWGameData sharedGameData].bubbleFactoryUpgradeTier > 0) {
if ([RWGameData sharedGameData].regularBubbleCount < [RWGameData sharedGameData].bubbleBankCapacity) {
[RWGameData sharedGameData].regularBubbleCount += [RWGameData sharedGameData].bubbleFactoryTickValue;
[[RWGameData sharedGameData] save];
} else {
NSLog(#"Capacity Reached! Capacity: %li", [RWGameData sharedGameData].bubbleBankCapacity);
}
if(self.delegate && [self.delegate respondsToSelector:#selector(StateUpdateForGameData:)])
[self.delegate StateUpdateForGameData:self];
} NSLog(#"Regular Bubble Count: %li", [RWGameData sharedGameData].regularBubbleCount);
}
Related
I have a NSMutableArray filled with objects of my Movie class wich i want to save but it doesn't work and i can not figure out why...
Movie.h:
#interface Movie : NSObject <NSCoding>{
NSString *name;
int year;
int length;
NSString *file_size;
int rating;
NSArray *genre;
NSString *plot;
}
#property (nonatomic, retain) NSString *name;
#property (nonatomic, assign) int year;
#property (nonatomic, assign) int length;
#property (nonatomic, retain, retain) NSString *file_size;
#property (nonatomic, assign) int rating;
#property (nonatomic, retain) NSArray *genre;
#property (nonatomic, retain) NSString *plot;
-(id) initWithName:(NSString*)newName year:(int)newYear length:(int)newLength filesize:(NSString*)newFileSize rating:(int)newRating genre:(NSArray*)newGenre plot:(NSString*)newPlot;
- (void) encodeWithCoder : (NSCoder *)encode ;
- (id) initWithCoder : (NSCoder *)decode;
#end
Movie.m:
#implementation Movie
#synthesize name;
#synthesize year;
#synthesize length;
#synthesize file_size;
#synthesize rating;
#synthesize genre;
#synthesize plot;
-(id)initWithName:(NSString *)newName year:(int)newYear length:(int)newLength filesize:(NSString *)newFileSize rating:(int)newRating genre:(NSArray *)newGenre plot:(NSString *)newPlot{
self.name = newName;
self.year = newYear;
self.length = newLength;
self.file_size = newFileSize;
self.rating = newRating;
self.genre = newGenre;
self.plot = newPlot;
return self;
}
- (void)encodeWithCoder:(NSCoder *)encode;
{
[encode encodeObject:name forKey:#"name"];
[encode encodeInt32:year forKey:#"year"];
[encode encodeInt32:length forKey:#"length"];
[encode encodeObject:file_size forKey:#"file_size"];
[encode encodeInt32:rating forKey:#"rating"];
[encode encodeObject:genre forKey:#"genre"];
[encode encodeObject:plot forKey:#"plot"];
}
- (id)initWithCoder:(NSCoder *)decode;
{
NSString *name_decode = [decode decodeObjectForKey:#"name"];
int year_decode = [decode decodeInt32ForKey:#"year"];
int length_decode = [decode decodeInt32ForKey:#"length"];
NSString *file_size_decode = [decode decodeObjectForKey:#"file_size"];
int rating_decode = [decode decodeInt32ForKey:#"rating"];
NSArray *genre_decode = [decode decodeObjectForKey:#"genre"];
NSString *plot_decode =[decode decodeObjectForKey:#"plot"];
return [self initWithName:name_decode year:year_decode length:length_decode filesize:file_size_decode rating:rating_decode genre:genre_decode plot:plot_decode];
}
#end
Save Action (Movies is the NSMutableArray containing my Objects):
NSUserDefaults *userDefault=[NSUserDefaults standardUserDefaults];
NSData *encodedData = [NSKeyedArchiver archivedDataWithRootObject:Movies];
[userDefault setObject:encodedData forKey:[NSString stringWithFormat:#"MOVIES"]];
Load Action:
NSData *decodedData = [userDefault objectForKey: [NSString stringWithFormat:#"MOVIES"]];
NSArray *decodedArray =[NSKeyedUnarchiver unarchiveObjectWithData: decodedData];
The returned Array is always (null)... i have no clue
I tried several different kind of code snippets i found on the internet and/or stackoverflow
Your Movie initWithName... method is incorrect. It needs to be:
- (instancetype)initWithName:(NSString *)newName year:(int)newYear length:(int)newLength filesize:(NSString *)newFileSize rating:(int)newRating genre:(NSArray *)newGenre plot:(NSString *)newPlot {
self = [super init];
if (self) {
self.name = newName;
self.year = newYear;
self.length = newLength;
self.file_size = newFileSize;
self.rating = newRating;
self.genre = newGenre;
self.plot = newPlot;
}
return self;
}
Also, you seem to be following a very out-of-date tutorial.
You don't need to declare the ivars for your properties.
You don't need the calls to #synthesize.
You should be using ARC instead of MRC, Therefore your retain properties should be strong (thought the NSString properties should be copy.
Your init methods should return instancetype, not id.
With all of that in mind, your Movie class should be as follows:
Movie.h
#interface Movie : NSObject <NSCoding>
#property (nonatomic, copy) NSString *name;
#property (nonatomic, assign) int year;
#property (nonatomic, assign) int length;
#property (nonatomic, copy) NSString *file_size;
#property (nonatomic, assign) int rating;
#property (nonatomic, strong) NSArray *genre;
#property (nonatomic, copy) NSString *plot;
- (instancetype)initWithName:(NSString *)newName year:(int)newYear length:(int)newLength filesize:(NSString *)newFileSize rating:(int)newRating genre:(NSArray *)newGenre plot:(NSString *)newPlot;
#end
Movie.m
#implementation Movie
- (instancetype)initWithName:(NSString *)newName year:(int)newYear length:(int)newLength filesize:(NSString *)newFileSize rating:(int)newRating genre:(NSArray *)newGenre plot:(NSString *)newPlot {
self = [super init];
if (self) {
_name = newName;
_year = newYear;
_length = newLength;
_file_size = newFileSize;
_rating = newRating;
_genre = newGenre;
_plot = newPlot;
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encode;
{
[encode encodeObject:self.name forKey:#"name"];
[encode encodeInt32:self.year forKey:#"year"];
[encode encodeInt32:self.length forKey:#"length"];
[encode encodeObject:self.file_size forKey:#"file_size"];
[encode encodeInt32:self.rating forKey:#"rating"];
[encode encodeObject:self.genre forKey:#"genre"];
[encode encodeObject:self.plot forKey:#"plot"];
}
- (instancetype)initWithCoder:(NSCoder *)decode;
{
NSString *name_decode = [decode decodeObjectForKey:#"name"];
int year_decode = [decode decodeInt32ForKey:#"year"];
int length_decode = [decode decodeInt32ForKey:#"length"];
NSString *file_size_decode = [decode decodeObjectForKey:#"file_size"];
int rating_decode = [decode decodeInt32ForKey:#"rating"];
NSArray *genre_decode = [decode decodeObjectForKey:#"genre"];
NSString *plot_decode =[decode decodeObjectForKey:#"plot"];
return [self initWithName:name_decode year:year_decode length:length_decode filesize:file_size_decode rating:rating_decode genre:genre_decode plot:plot_decode];
}
#end
You don't show how you create and populate your Movies variable (which should be named movies, not Movies. Make sure it isn't nil.
Also, don't needlessly use stringWithFormat.
Your saving code should be:
NSUserDefaults *userDefault=[NSUserDefaults standardUserDefaults];
NSData *encodedData = [NSKeyedArchiver archivedDataWithRootObject:movies];
[userDefault setObject:encodedData forKey:#"MOVIES"];
and your loading code should be:
NSData *decodedData = [userDefault objectForKey:#"MOVIES"];
NSArray *decodedArray = [NSKeyedUnarchiver unarchiveObjectWithData: decodedData];
A quick test is to see if the mutable array is actually not nil itself. Try outputting the mutable array before setting it in userDefaults.
Make sure the mutable array is initialized before trying to add objects to it.
movies = [[NSMutableArray alloc] init];
I'm having trouble with setting and accessing long properties on a Singleton object. Every time I try to access a long property it returns -1.
My singleton interface file is as follows:
#interface gameData : NSObject <NSCoding>
#property (assign, nonatomic) long score;
#property (assign, nonatomic) long level;
#property (assign, nonatomic) long riddlesCompleted;
#property (assign, nonatomic) long hints;
#property (assign, nonatomic) long firstLetters;
#property (assign, nonatomic) long answers;
+(instancetype)sharedGameData;
-(void)reset;
-(void)save;
#end
Then the implementation file sets up the encoders and decoders as follows:
-(void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeDouble:self.score forKey:gameDataScoreKey];
[aCoder encodeDouble:self.level forKey:gameDataLevelKey];
[aCoder encodeDouble:self.riddlesCompleted forKey:gameDataRiddlesCompletedKey];
[aCoder encodeDouble:self.hints forKey:gameDataHintsKey];
[aCoder encodeDouble:self.firstLetters forKey:gameDataFirstLettersKey];
[aCoder encodeDouble:self.answers forKey:gameDataAnswersKey];
}
-(instancetype)initWithCoder:(NSCoder *)decoder{
self = [self init];
if (self) {
_score = [decoder decodeDoubleForKey:gameDataScoreKey];
_level = [decoder decodeDoubleForKey:gameDataLevelKey];
_riddlesCompleted = [decoder decodeDoubleForKey:gameDataRiddlesCompletedKey];
_hints = [decoder decodeDoubleForKey:gameDataHintsKey];
_firstLetters = [decoder decodeDoubleForKey:gameDataFirstLettersKey];
_answers = [decoder decodeDoubleForKey:gameDataAnswersKey];
}
return self;
}
+(instancetype) sharedGameData{
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [self loadInstance];
});
return sharedInstance;
}
Values are initialised as follows:
-(id)init{
if(self = [super init]){
_score = 500;
_riddlesCompleted = 0;
_level = 1;
_hints = 3;
_firstLetters = 3;
_answers = 3;
}
return self;
}
and then the instance is loaded:
+(NSString*)filePath{
static NSString* filePath = nil;
if (!filePath) {
filePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES) firstObject]
stringByAppendingString:#"gameData"];
}
return filePath;
}
+(instancetype)loadInstance{
NSData* decodeData = [NSData dataWithContentsOfFile:[gameData filePath]];
if (decodeData) {
gameData* gameData = [NSKeyedUnarchiver unarchiveObjectWithData:decodeData];
return gameData;
}
return [[gameData alloc] init];
}
Then elsewhere in the application when I try to access these values I am not able to access the values of hints, firstletters or answers.
If I try logging the values as follows:
NSLog([NSString stringWithFormat:#"%li", [gameData sharedGameData].score] );
NSLog([NSString stringWithFormat:#"%li", [gameData sharedGameData].hint] );
NSLog([NSString stringWithFormat:#"%li", [gameData sharedGameData].answers]);
NSLog([NSString stringWithFormat:#"%li", [gameData sharedGameData].firstLetters]);
The output I get is 500 for score but for all the others I get 0 even though they are initialised in the gameData.m file with values 3.
Just a guess:
In loadInstance() you read the values from the file, so if there is a file you won't get in the init() where you set the values.
To be sure there is no gamedata-file you should reset the simulator oder delete the app from the device and try again.
The variable 'bubbleBankCapacity' is expected to return as 500 and be compared to the 'regularBubbleCount' variable in the comparison below, but instead returns as 0 which effectively makes the condition false given that the regularBubbleCount is greater than 0. Why is this returning a 0 when it has been set to initialize as 500?
AppDelegate.m
#import "AppDelegate.h"
#interface AppDelegate ()
#end
#implementation AppDelegate
-(void)timerCalled
{
NSLog(#"Timer Called");
if ([RWGameData sharedGameData].bubbleFactoryUpgradeTier > 0) {
if ([RWGameData sharedGameData].regularBubbleCount < [RWGameData sharedGameData].bubbleBankCapacity) {
NSLog(#"bubbleFactoryUpgradeTier: %li", [RWGameData sharedGameData].bubbleFactoryUpgradeTier);
[RWGameData sharedGameData].regularBubbleCount += [RWGameData sharedGameData].bubbleFactoryTickValue;
NSLog(#"bubbleFactoryTickValue: %i", [RWGameData sharedGameData].bubbleFactoryTickValue);
[[RWGameData sharedGameData] save];
} else {
NSLog(#"Capacity Reached! Capacity: %li", [RWGameData sharedGameData].bubbleBankCapacity);
}
} NSLog(#"Regular Bubble Count: %li", [RWGameData sharedGameData].regularBubbleCount);
}
RWGameData.h
#import <Foundation/Foundation.h>
#interface RWGameData : NSObject <NSCoding>
#property (assign, nonatomic) long regularBubbleCount;
#property (assign, nonatomic) long premiumBubbleCount;
#property (assign, nonatomic) long megaBubbleUpgradeTier;
#property (assign, nonatomic) long bubbleFactoryUpgradeTier;
#property (assign, nonatomic) long bubblersUpgradeTier;
#property (assign, nonatomic) long mysteryBubbleUpgradeTier;
#property (assign, nonatomic) long bubbleBankUpgradeTier;
#property (assign, nonatomic) int megaBubblePopValue;
#property (assign, nonatomic) int bubbleFactoryTickValue;
#property (assign, nonatomic) long bubbleBankCapacity;
+(instancetype)sharedGameData;
-(void)reset;
-(void)save;
#end
RWGameData.m
#import "RWGameData.h"
#implementation RWGameData
static NSString* const SSGameDataRegularBubbleCountKey = #"regularBubbleCount";
static NSString* const SSGameDataPremiumBubbleCountKey = #"premiumBubbleCount";
static NSString* const SSGameDataMegaBubbleUpgradeTierKey = #"megaBubbleUpgradeTier";
static NSString* const SSGameDataBubbleFactoryUpgradeTierKey = #"bubbleFactoryUpgradeTier";
static NSString* const SSGameDataBubblersUpgradeTierKey = #"bubblersUpgradeTier";
static NSString* const SSGameDataMysteryBubbleUpgradeTierKey = #"mysteryBubbleUpgradeTier";
static NSString* const SSGameDataBubbleBankUpgradeTierKey = #"bubbleBankUpgradeTier";
static NSString* const SSGameDataMegaBubblePopValueKey = #"megaBubblePopValueKey";
static NSString* const SSGameDataBubbleFactoryTickValueKey = #"bubbleFactoryTickValueKey";
static NSString* const SSGameDataBubbleBankCapacityKey = #"bubbleBankCapacityKey";
+ (instancetype)sharedGameData {
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [self loadInstance];
});
return sharedInstance;
}
-(void)reset {
self.regularBubbleCount = 0;
self.premiumBubbleCount = 0;
self.megaBubbleUpgradeTier = 0;
self.bubbleFactoryUpgradeTier = 0;
self.bubblersUpgradeTier = 0;
self.mysteryBubbleUpgradeTier = 0;
self.bubbleBankUpgradeTier = 0;
self.megaBubblePopValue = 1;
self.bubbleFactoryTickValue = 1;
self.bubbleBankCapacity = 500;
}
- (void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeDouble:self.regularBubbleCount forKey: SSGameDataRegularBubbleCountKey];
[encoder encodeDouble:self.premiumBubbleCount forKey: SSGameDataPremiumBubbleCountKey];
[encoder encodeDouble:self.megaBubbleUpgradeTier forKey: SSGameDataMegaBubbleUpgradeTierKey];
[encoder encodeDouble:self.bubbleFactoryUpgradeTier forKey: SSGameDataBubbleFactoryUpgradeTierKey];
[encoder encodeDouble:self.bubblersUpgradeTier forKey: SSGameDataBubblersUpgradeTierKey];
[encoder encodeDouble:self.mysteryBubbleUpgradeTier forKey: SSGameDataMysteryBubbleUpgradeTierKey];
[encoder encodeDouble:self.bubbleBankUpgradeTier forKey: SSGameDataBubbleBankUpgradeTierKey];
[encoder encodeDouble:self.megaBubblePopValue forKey: SSGameDataMegaBubblePopValueKey];
[encoder encodeDouble:self.bubbleFactoryTickValue forKey: SSGameDataBubbleFactoryTickValueKey];
[encoder encodeDouble:self.bubbleBankCapacity forKey: SSGameDataBubbleBankCapacityKey];
}
- (instancetype)initWithCoder:(NSCoder *)decoder
{
self = [self init];
if (self) {
_regularBubbleCount = [decoder decodeDoubleForKey: SSGameDataRegularBubbleCountKey];
_premiumBubbleCount = [decoder decodeDoubleForKey: SSGameDataPremiumBubbleCountKey];
_megaBubbleUpgradeTier = [decoder decodeDoubleForKey: SSGameDataMegaBubbleUpgradeTierKey];
_bubbleFactoryUpgradeTier = [decoder decodeDoubleForKey: SSGameDataBubbleFactoryUpgradeTierKey];
_bubblersUpgradeTier = [decoder decodeDoubleForKey: SSGameDataBubblersUpgradeTierKey];
_mysteryBubbleUpgradeTier = [decoder decodeDoubleForKey: SSGameDataMysteryBubbleUpgradeTierKey];
_bubbleBankUpgradeTier = [decoder decodeDoubleForKey: SSGameDataBubbleBankUpgradeTierKey];
_megaBubblePopValue = [decoder decodeDoubleForKey: SSGameDataMegaBubblePopValueKey];
_bubbleFactoryTickValue = [decoder decodeDoubleForKey: SSGameDataBubbleFactoryTickValueKey];
_bubbleBankCapacity = [decoder decodeDoubleForKey: SSGameDataBubbleBankCapacityKey];
}
return self;
}
+(NSString*)filePath
{
static NSString* filePath = nil;
if (!filePath) {
filePath =
[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]
stringByAppendingPathComponent:#"gamedata"];
}
return filePath;
}
+(instancetype)loadInstance
{
NSData* decodedData = [NSData dataWithContentsOfFile: [RWGameData filePath]];
if (decodedData) {
RWGameData* gameData = [NSKeyedUnarchiver unarchiveObjectWithData:decodedData];
return gameData;
}
return [[RWGameData alloc] init];
}
-(void)save
{
NSData* encodedData = [NSKeyedArchiver archivedDataWithRootObject: self];
[encodedData writeToFile:[RWGameData filePath] atomically:YES];
}
#end
You need to initialize the bubbleBankCapacity variable in AppDelegate.m inside your method.
Solved.
I went ahead and declared a boolean property to RWGameData and tasked the reset method to set it to true when the reset method had been called. Then I went ahead and adjusted - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions like so:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
if (![RWGameData sharedGameData].dataIsInitialized) {
[[RWGameData sharedGameData] reset];
}
NSTimer *timer;
timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(timerCalled) userInfo:nil repeats:YES];
return YES;
}
Thank you to everyone who offered a solution to this problem. I greatly appreciate it!
I was trying to solve assignment 2 from Stanford iOS7 development (Matchismo card game)
The game works fine. Now I have to add the Restart function. If the user press on the restart button, the game restarts (it deals new cards and it resets the score)
my game model is the #property (nonatomic, strong) CardMatchingGame *game;
this is the code for the CardMatchingGame.m:
#import "CardMatchingGame.h"
#import "PlayingCardDeck.h"
#interface CardMatchingGame()
#property (nonatomic, readwrite) NSInteger score;
#property (nonatomic, strong) NSMutableArray *cards;
#end
#implementation CardMatchingGame
static const int MATCH_BONUS = 4;
static const int MATCH_PENALTY = 2;
static const int COST_TO_CHOOSE = 1;
-(NSMutableArray *)cards{
if(!_cards) _cards = [[NSMutableArray alloc]init];
return _cards;
}
-(instancetype)initWithCardCount:(NSUInteger)count usingDeck:(Deck *)deck{
self = [super init];
if(self){
for(int i=0; i < count; i++){
Card *card = [deck drawRandomCard];
if(card){
[self.cards addObject:card];
} else{
self = nil;
break;
}
}
}
return self;
}
-(void)chooseCardAtIndex:(NSUInteger)index{
Card *card = [self cardAtIndex:index];
if(!card.isMatched){
if(card.isChosen){
card.chosen = NO;
} else{
for(Card *otherCard in self.cards){
if(otherCard.isChosen && !otherCard.isMatched){
int matchScore = [card match:#[otherCard]];
if(matchScore){
self.score += matchScore * MATCH_BONUS;
card.matched = YES;
otherCard.matched = YES;
} else{
self.score -= MATCH_PENALTY;
otherCard.chosen = NO;
}
break;
}
}
self.score -= COST_TO_CHOOSE;
card.chosen = YES;
}
}
}
-(Card *)cardAtIndex:(NSUInteger)index{
return (index < [self.cards count]) ? self.cards[index] : nil;
}
#end
here is my CardGameViewController.m:
#import "CardGameViewController.h"
#import "PlayingCardDeck.h"
#import "CardMatchingGame.h"
#interface CardGameViewController ()
#property (nonatomic, strong) Deck *deck;
#property (nonatomic, strong) CardMatchingGame *game;
#property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *cardsCollection;
#property (weak, nonatomic) IBOutlet UILabel *scoreLabel;
#end
#implementation CardGameViewController
#synthesize game = _game;
-(CardMatchingGame *)game{
if(!_game) _game = [[CardMatchingGame alloc] initWithCardCount:[self.cardsCollection count]
usingDeck:self.deck];
return _game;
}
-(Deck *)deck{
if(!_deck) _deck = [[PlayingCardDeck alloc] init];
return _deck;
}
- (IBAction)touchRestartButton:(id)sender {
self.game = nil;
[self updateUI];
}
- (IBAction)touchCardButton:(UIButton *)sender {
int chosenButtonIndex = [self.cardsCollection indexOfObject:sender];
[self.game chooseCardAtIndex:chosenButtonIndex];
[self updateUI];
}
-(void)updateUI{
for(UIButton *cardButton in self.cardsCollection){
int buttonIndex = [self.cardsCollection indexOfObject:cardButton];
Card *card = [self.game cardAtIndex:buttonIndex];
[cardButton setTitle:[self titleForCard:card] forState:UIControlStateNormal];
[cardButton setBackgroundImage:[self backgroundImageForCard:card] forState:UIControlStateNormal];
cardButton.enabled = !card.isMatched;
}
self.scoreLabel.text = [NSString stringWithFormat:#"Score: %d", self.game.score];
}
-(NSString *)titleForCard:(Card *)card{
return card.isChosen ? card.contents : #"";
}
-(UIImage *)backgroundImageForCard:(Card *)card{
return [UIImage imageNamed: card.isChosen ? #"cardfront" : #"cardback"];
}
#end
In order to restart the game, I think I should simply re-initialize the property CardMatchingGame *game.
This is what I tried to do, by setting self.game = nil; Then it should automatically be re-initialized in the getter of game.
This is, indeed, the solution that I found on the internet. However, in my program it doesn't work. *game is set to nil and never restored, so the game ends when you click restart.
Could you please help me to figure out why self.game = nil doesn't work in my case?
- (IBAction)startover:(UIButton *)sender {
self.game= [[CardMatchingGame alloc] initWithCardCount:[self.cardButtons count] usingDeck:[self createDeck]];
[self updateUI];
}
If your program has the lazy init style recommended, there is no need for a new method such as start over. You are correct to set self.game to nil, now a call the the getter will start a new instance of the game. I did it by making a call to UIUpdate right after the self.game = nil. That has a call to the getter and lazily inits a new instance of the game.
This question already has answers here:
How to store custom objects in NSUserDefaults
(7 answers)
Closed 9 years ago.
I am trying to save an NSDictionary to my NSUserDefualts.
The dictionary consists of 3 different custom classes.
#interface PastOrder : NSObject <NSCoding>
{
NSDate *timeIn;
NSDate *timeOut;
NSString *status;
NSMutableArray *myItems;
}
#property (nonatomic, retain) NSDate *timeIn;
#property (nonatomic, retain) NSDate *timeOut;
#property (nonatomic, retain) NSString *status;
#property (nonatomic, retain) NSMutableArray *myItems;
#end
#implementation PastOrder
#synthesize timeIn, timeOut, status, myItems;
#define PastOrderTimeInKey #"PastOrderTimeInKey"
#define PastOrderTimeOutKey #"PastOrderTimeOutKey"
#define PastOrderStatusKey #"PastOrderStatusKey"
#define PastOrderMyItemsKey #"PastOrderMyItemsKey"
-(id)initWithCoder:(NSCoder*)decoder
{
self = [super init];
if(self)
{
self.timeIn = [decoder decodeObjectForKey:PastOrderTimeInKey];
self.timeOut = [decoder decodeObjectForKey:PastOrderTimeOutKey];
self.status = [decoder decodeObjectForKey:PastOrderStatusKey];
self.myItems = [decoder decodeObjectForKey:PastOrderMyItemsKey];
}
return self;
}
-(void)encodeWithCoder:(NSCoder*)encoder
{
[encoder encodeObject:self.timeIn forKey:PastOrderTimeInKey];
[encoder encodeObject:self.timeOut forKey:PastOrderTimeOutKey];
[encoder encodeObject:self.status forKey:PastOrderStatusKey];
[encoder encodeObject:self.myItems forKey:PastOrderMyItemsKey];
}
-(void)dealloc
{
self.timeIn = nil;
self.timeOut = nil;
self.status = nil;
self.myItems = nil;
}
#end
#interface PastOrderItem : NSObject <NSCoding>
{
NSNumber *itemID;
NSString *status;
NSMutableArray *itemChoices;
}
#property (nonatomic, retain) NSNumber *itemID;
#property (nonatomic, retain) NSString *status;
#property (nonatomic, retain) NSMutableArray *itemChoices;
#end
#implementation PastOrderItem
#synthesize itemID,status,itemChoices;
#define PastOrderItemItemIDKey #"PastOrderItemItemIDKey"
#define PastOrderItemStatusKey #"PastOrderItemStatusKey"
#define PastOrderItemItemChoicesKey #"PastOrderItemItemChoicesKey"
-(id)initWithCoder:(NSCoder*)decoder
{
self = [super init];
if(self)
{
self.itemID = [decoder decodeObjectForKey:PastOrderItemItemIDKey];
self.itemChoices = [decoder decodeObjectForKey:PastOrderItemItemChoicesKey];
self.status = [decoder decodeObjectForKey:PastOrderItemStatusKey];
}
return self;
}
-(void)encodeWithCoder:(NSCoder*)encoder
{
[encoder encodeObject:self.itemID forKey:PastOrderItemItemIDKey];
[encoder encodeObject:self.itemChoices forKey:PastOrderItemItemChoicesKey];
[encoder encodeObject:self.status forKey:PastOrderItemStatusKey];
}
-(void)dealloc
{
self.itemID = nil;
self.itemChoices = nil;
self.status = nil;
}
#end
#interface PastOrderItemChoice : NSObject <NSCoding>
{
NSNumber *modifierID;
NSNumber *modifierChoice;
}
#property (nonatomic, retain) NSNumber *modifierID;
#property (nonatomic, retain) NSNumber *modifierChoice;
#end
#implementation PastOrderItemChoice
#synthesize modifierID, modifierChoice;
#define PastOrderItemChoiceModifierIDKey #"PastOrderItemChoiceModifierIDKey"
#define PastOrderItemChoiceModifierChoiceKey #"PastOrderItemChoiceModifierChoiceKey"
-(id)initWithCoder:(NSCoder*)decoder
{
self = [super init];
if(self)
{
self.modifierID = [decoder decodeObjectForKey:PastOrderItemChoiceModifierIDKey];
self.modifierChoice = [decoder decodeObjectForKey:PastOrderItemChoiceModifierChoiceKey];
}
return self;
}
-(void)encodeWithCoder:(NSCoder*)encoder
{
[encoder encodeObject:self.modifierID forKey:PastOrderItemChoiceModifierIDKey];
[encoder encodeObject:self.modifierChoice forKey:PastOrderItemChoiceModifierChoiceKey];
}
-(void)dealloc
{
self.modifierID = nil;
self.modifierChoice = nil;
}
#end
Those are the three classes that will be inside this NSDictionary.
Here is how I Load and Save it.
-(void)SavePrefs
{
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSData* data=[NSKeyedArchiver archivedDataWithRootObject:self.myDictionary];
[prefs setObject:data forKey:#"SavedOrders"];
[prefs synchronize];
}
- (id)init
{
self = [super init];
if (self)
{
NSData* data = [[NSUserDefaults standardUserDefaults] objectForKey:#"SavedOrders"];
self.myDictionary = [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
return self;
}
I have experimented with the code a bit, and best I have to far, is that when I save the dictionary, it was 135 bytes, same as when I loaded it, but it still didnt fill the dictionary up. So I am at a loss.
Your code seems to be good. I can't find a mistake so try to change line:
self.myDictionary = [NSKeyedUnarchiver unarchiveObjectWithData:data];
to
id unknownObject = [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSLog(#"%#",[unknownObject class]);
And look # the console. Maybe you should also try casting if the output will be dictionary. So try to change this to:
self.myDictionary = (NSDictionary*)[NSKeyedUnarchiver unarchiveObjectWithData:data];
EDIT
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:#"object1",#"key1",#"object2",#"key2",#"object3",#"key3", nil];
NSLog(#"before: %#",dictionary);
NSData *myData = [NSKeyedArchiver archivedDataWithRootObject:dictionary];
NSDictionary *myDictionary = (NSDictionary*) [NSKeyedUnarchiver unarchiveObjectWithData:myData];
NSLog(#"after: %#",myDictionary);
Output:
2013-11-13 14:32:31.369 DemoM[175:60b] before: {
key1 = object1;
key2 = object2;
key3 = object3;
}
2013-11-13 14:32:31.372 DemoM[175:60b] after: {
key1 = object1;
key2 = object2;
key3 = object3;
}