Advice on High Score persistence (iPhone, Cocoa Touch) - iphone

I was curious what is considered the better way to manage the reading and writing of a High Score plist file. My High Score class is:
#interface HighScore : NSObject <NSCoding> {
NSString *name;
int score;
int level;
int round;
NSDate *date;
}
Now, I could do method A, add NSCoding methods:
- (void) encodeWithCoder: (NSCoder *) coder {
[coder encodeObject: name
forKey: kHighScoreNameKey];
[coder encodeInt: score
forKey: kHighScoreScoreKey];
[coder encodeInt: level
forKey: kHighScoreLevelKey];
[coder encodeInt: round
forKey: kHighScoreRoundKey];
[coder encodeObject: date
forKey: kHighScoreDateKey];
} // encodeWithCoder
- (id) initWithCoder: (NSCoder *) decoder {
if (self = [super init]) {
self.name = [decoder decodeObjectForKey: kHighScoreNameKey];
self.score = [decoder decodeIntForKey: kHighScoreScoreKey];
self.level = [decoder decodeIntForKey: kHighScoreLevelKey];
self.round = [decoder decodeIntForKey: kHighScoreRoundKey];
self.date = [decoder decodeObjectForKey: kHighScoreDateKey];
}
return (self);
} // initWithCoder
And write it all out with:
if (![NSKeyedArchiver archiveRootObject:highScoresList toFile:path]) ...
Reading it back in would be pretty straight forward. However the plist file, IMHO, looks like crap.
Or I could employ method B:
NSMutableArray *array = [NSMutableArray arrayWithCapacity:20];;
for (HighScore *hs in highScoresList) {
NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:
hs.name, kHighScoreNameKey,
[NSNumber numberWithInteger:hs.score], kHighScoreScoreKey,
[NSNumber numberWithInteger:hs.level], kHighScoreLevelKey,
[NSNumber numberWithInteger:hs.round], kHighScoreRoundKey,
hs.date, kHighScoreDateKey,
nil];
[array addObject:dict];
[dict release];
}
and write it all out with:
if (![array writeToFile:path atomically:YES]) ...
Reading it back in is a tiny bit harder. But the plist file looks much cleaner (smaller and compact).
Any thoughts? Am I missing something that is much simpler? (I want to keep the High Scores separate from NSUserDefaults so I am not using that).

Both your ways look fine to me. There is also Core Data in the 3.0 OS, although it might be overkill if all you want to save is a single high score value.

I'm not sure that I understand your objections! Both should work just fine.
Personally I prefer method A. I think it makes sense that an object knows how to encode itself. It makes maintenance easier and any changes more localised. Plus it probably uses less memory.

check out this question, maybe it's useful for your app

I went with method B because: 1. The plist file is more readable and 2. I can save off some file and class version numbering into this method easily:
In my HighScore class:
- (id)initFromDictionary: (NSDictionary *)dict;
{
if (self = [super init]) {
self.name = [dict objectForKey:kHighScoreNameKey];
self.score = [[dict objectForKey:kHighScoreScoreKey] integerValue];
self.game = [[dict objectForKey:kHighScoreGameKey] integerValue];
self.level = [[dict objectForKey:kHighScoreLevelKey] integerValue];
self.date = [dict objectForKey:kHighScoreDateKey];
}
return (self);
}
- (NSDictionary *)putIntoDictionary;
{
NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:
name, kHighScoreNameKey,
[NSNumber numberWithInt:score], kHighScoreScoreKey,
[NSNumber numberWithInt:game], kHighScoreGameKey,
[NSNumber numberWithInt:level], kHighScoreLevelKey,
date, kHighScoreDateKey,
nil];
return dict;
}
And in my HighScoreTable class:
- (id) load
{
NSString *path = [self getFilePath];
// [self clear];
NSDictionary *rootLevelPlistDict = [NSDictionary dictionaryWithContentsOfFile:path];
int versNum = [[rootLevelPlistDict objectForKey:kHighScoreVersKey] integerValue];
if (versNum == kHighScoreVersNum) {
NSArray *insideArray = [rootLevelPlistDict objectForKey:kHighScoresKey];
NSDictionary *dict;
for (dict in insideArray) {
HighScore *hs = [[HighScore alloc] initFromDictionary:dict];
[highScoresList addObject:hs];
[hs release];
}
}
return sharedHighScoresSingleton;
}
- (void) save
{
if (!changed)
return;
NSString *path = [self getFilePath];
NSMutableArray *array = [NSMutableArray arrayWithCapacity:kNumberOfHighScores];
for (HighScore *hs in highScoresList) {
NSDictionary *dict = [hs putIntoDictionary];
[array addObject:dict];
[dict release];
}
NSDictionary *rootLevelPlistDict = [[NSDictionary alloc] initWithObjectsAndKeys:
[[[NSBundle mainBundle] infoDictionary]
objectForKey:(NSString*)kCFBundleNameKey], kHighScoreAppNameKey,
[NSNumber numberWithInt:kHighScoreHeaderVersNum], kHighScoreHeaderVersKey,
[NSNumber numberWithInt:kHighScoreVersNum], kHighScoreVersKey,
[NSDate date], kHighScoreCreationKey,
array, kHighScoresKey,
nil];
if (![rootLevelPlistDict writeToFile:path atomically:YES])
NSLog(#"not successful in writing the high scores");
[rootLevelPlistDict release];
}

Related

Storing a NSArray of my Custom Objects in NSUserDefaults

The requirement is that I want to store NSArray of my custom objects in NSUserDefaults.
Following is the code from my example
- (void)viewDidLoad
{
[super viewDidLoad];
sampleArray=[[NSMutableArray alloc]init];
MyClass *obj1=[[MyClass alloc]init];
obj1.name=#"Reetu";
obj1.countOpen=1;
NSArray *subArray = [[NSArray alloc]initWithObjects:#"likes131",#"likes132", #"likes133", nil];
obj1.hobbies = [[NSArray alloc]initWithObjects:#"like11", #"like12", subArray, nil];
[sampleArray addObject:obj1];
MyClass *obj2=[[MyClass alloc]init];
obj2.name=#"Pinku";
obj2.countOpen=2;
NSArray *subArray2 = [[NSArray alloc]initWithObjects:obj1 ,#"likes231",#"likes232", #"likes233", obj1 ,nil];
obj2.hobbies = [[NSArray alloc]initWithObjects:#"like21", #"like22", subArray2 ,nil];
[sampleArray addObject:obj2];
MyClass *obj3=[[MyClass alloc]init];
obj3.name=#"Mike";
obj3.countOpen=6;
obj3.hobbies = [[NSArray alloc]initWithObjects:obj1 , obj2 ,#"likes000", nil];
[sampleArray addObject:obj3];
//First lets encode it
NSUserDefaults *userDefault=[NSUserDefaults standardUserDefaults];
NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:sampleArray];
[userDefault setObject:myEncodedObject forKey:[NSString stringWithFormat:#"sample"]];
[userDefault synchronize];
//Lets decode it now
NSData *myDecodedObject = [userDefault objectForKey: [NSString stringWithFormat:#"sample"]];
NSArray *decodedArray =[NSKeyedUnarchiver unarchiveObjectWithData: myDecodedObject];
//Print the array received from User's Default
for (MyClass *item in decodedArray) {
NSLog(#"name=%#",item.name);
NSLog(#"LIKES TO %#",item.hobbies);
}
}
This is my custom class confirming to the NSCoding protocol
- (void)encodeWithCoder:(NSCoder *)encoder
{
//Encode properties, other class variables, etc
[encoder encodeObject:self.name forKey:#"name"];
[encoder encodeObject:[NSNumber numberWithInt:self.countOpen] forKey:#"destinationCode"];
[encoder encodeObject:self.hobbies forKey:#"likesTo"];
}
- (id)initWithCoder:(NSCoder *)decoder
{
self = [super init];
if( self != nil )
{
self.name = [decoder decodeObjectForKey:#"name"];
self.countOpen = [[decoder decodeObjectForKey:#"countOpen"] intValue];
self.hobbies = [decoder decodeObjectForKey:#"likesTo"];
}
return self;
}
here is the output:-
2013-10-22 17:01:47.118 Sample[1056:c07] name=Reetu
2013-10-22 17:01:47.120 Sample[1056:c07] LIKES TO (
like11,
like12,
(
likes131,
likes132,
likes133
)
)
2013-10-22 17:01:47.121 Sample[1056:c07] name=Pinku
2013-10-22 17:01:47.123 Sample[1056:c07] LIKES TO (
like21,
like22,
(
"<MyClass: 0x6e32910>",
likes231,
likes232,
likes233,
"<MyClass: 0x6e32910>"
)
)
2013-10-22 17:01:47.125 Sample[1056:c07] name=Mike
2013-10-22 17:01:47.127 Sample[1056:c07] LIKES TO (
"<MyClass: 0x6e32910>",
"<MyClass: 0x6e1f610>",
likes000
)
The problem is <MyClass: 0X632910>. I was expecting it to be contents of obj1 itself.
The problem isn't with NSUserDefaults. It's with how you are printing the information out:
You should override -(NSString*) description, probably to read something like this:
-(NSString*) description
{
return [NSString stringWithFormat:#"<%# - name:%# open:%d>", self.class self.name, self.countOpen];
}
You are not logging the way like you are adding the elements to the array. You are adding a MyClass object to the second array but you are expecting its hobbies NSArray to be printed.
Change your logging function like this. It will print corretly until the second object. For the third object you have to write another for loop in the function. Because your object hierarchy is like that.
for (MyClass *item in decodedArray) {
NSLog(#"name=%#",item.name);
if ([item.technologies isKindOfClass:[MyClass class]]) {
for (MyClass *item in arr) {
NSLog(#"name=%#",item.name);
NSLog(#"LIKES TO %#",item.hobbies);
}
}
else{
NSLog(#"LIKES TO %#",item.hobbies);
}
}

How to swap `NSMutableDictionary` key and values in place?

I have a NSMutableDictionary and I want to swap values & keys. i.e, after swapping values becomes keys and its corresponding keys with become values All keys and values are unique. Looking for an in place solution because size is very big . Also, the keys and values are NSString objects
NSMutableDictionary *d = [NSMutableDictionary dictionaryWithDictionary:#{
#"key1" : #"value1",
#"key2" : #"value2"}];
for (NSString *key in [d allKeys]) {
d[d[key]] = key;
[d removeObjectForKey:key];
}
NSLog(#"%#", d); // => { value1 : key1,
// value2 : key2 }
Assumptions
unique values (as they will become keys)
values conform to NSCopying (same as above)
no value is equal to any key (otherwise colliding names will be lost in the process)
Here is another way to invert dictionary. The simplest for me.
NSArray *keys = dictionary.allKeys;
NSArray *values = [dictionary objectsForKeys:keys notFoundMarker:[NSNull null]];
[dictionary removeAllObjects]; // In case of huge data sets release the contents.
NSDictionary *invertedDictionary = [NSDictionary dictionaryWithObjects:keys forKeys:values];
[dictionary setDictionary:invertedDictionary]; // In case you want to use the original dictionary.
EDIT: I had written a few lines of codes to get the OP started into the task of creating his own algorithm. The answer was not well received so I have crafted a full implementation of an algorithm that does what he asks, and goes one step further.
Advantages:
Makes no assumptions regarding the contents of the dictionary, for example, the values need not conform to the 'NSCopying' protocol
Transverses the whole hierarchy of a collection, swapping all the keys
It's fast since it uses recursion and fast enumeration
Does not alter the contents of the original dictionary, it creates a brand new one
Code has been implemented through categories to both collections:
#interface NSDictionary (Swapping)
- (NSDictionary *)dictionaryBySwappingKeyWithValue;
#end
#interface NSDictionary (Swapping)
- (NSDictionary *)dictionaryBySwappingKeyWithValue
{
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithCapacity:self.count];
[self enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
id newKey = nil;
if ([value isKindOfClass:[NSDictionary class]]) {
newKey = [value dictionaryBySwappingKeyWithValue];
} else if ([value isKindOfClass:[NSArray class]]) {
newKey = [value arrayBySwappingKeyWithValue];
} else {
newKey = value;
}
if (![newKey conformsToProtocol:#protocol(NSCopying)]) {
newKey = [NSValue valueWithNonretainedObject:newKey];
}
mutableDictionary[newKey] = key;
}];
return [NSDictionary dictionaryWithDictionary:mutableDictionary];
}
#end
and...
#interface NSArray (Swapping)
- (NSArray *)arrayBySwappingKeyWithValue;
#end
#implementation NSArray (Swapping)
- (NSArray *)arrayBySwappingKeyWithValue
{
NSMutableArray *mutableArray = [NSMutableArray arrayWithCapacity:self.count];
[self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj isKindOfClass:[NSDictionary class]]) {
NSDictionary *newDict = [obj dictionaryBySwappingKeyWithValue];
mutableArray[idx] = newDict;
} else if ([obj isKindOfClass:[NSArray class]]) {
NSArray *newArray = [obj arrayBySwappingKeyWithValue];
mutableArray[idx] = newArray;
} else {
mutableArray[idx] = obj;
}
}];
return [NSArray arrayWithArray:mutableArray];
}
#end
As an example, assume you have a dictionary with the following structure:
UIView *view = [[UIView alloc] init];
NSDictionary *dict = #{#"1" : #"a",
#"2" : #[ #{ #"5" : #"b" } ],
#"3" : #{#"6" : #"c"},
#"7" : view};
NSDictionary *newDict = [dict dictionaryBySwappingKeyWithValue];
Printing the newDict object in the console will give you this output:
(lldb) po mutableDictionary
{
a = 1;
({b = 5;}) = 2;
{c = 6;} = 3;
"<30b50617>" = 7;
}
As you can see, not only have the keys and values been swapped at the first level of the hierarchy, but deep inside each collection.
"<30b50617>" represents the UIView object wrapped inside a NSValue. Since UIView does not comply to the NSCopying protocol, it needs to be handled this way if you want it to be a key in your collection.
Note: Code was done in a couple of minutes. Let me know if I missed something.
for (NSString *key in [myDictionary allKeys]) {
NSString *value = [responseDataDic objectForKey:key];
[myDictionary removeObjectForKey:key];
[myDictionary addObject:key forKey:value];
}
Assumption:
No key = value;
Complexity:
No extra space required. Will loop through once and replace all key value pairs.
NSArray* allKeys = [theDict allKeys];
NSArray* allValues = [theDict allValues];
NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithObjects:allKeys forKeys:allValues];

Modifying content from new dictionary also modifies the parent dictionary data

As I have a requirement to add similar objects into the array, I have created new dictionary in such a way.
NSMutableDictionary* existingStepDict = [[[arrayForSteps objectAtIndex:0] mutableCopy] autorelease];
[arrayForSteps addObject:existingStepDict];
[existingStepDict release];
Now, what happens here is that later when I change something in any one of the dictionary, the other one also gets updated. I require both these dictionaries to behave independently.
For that I went through Deep-copy of dictionaries whose code is like this.
NSMutableDictionary* existingStepDict = [[[arrayForSteps objectAtIndex:0] mutableCopy] autorelease];
NSMutableDictionary* destination = [NSMutableDictionary dictionaryWithCapacity:0];
NSDictionary *deepCopy = [[NSDictionary alloc] initWithDictionary:existingStepDict copyItems: YES];
if (deepCopy) {
[destination addEntriesFromDictionary: deepCopy];
[deepCopy release];
}
//add Properties array to Steps Dictionary
[arrayForSteps addObject:destination];
But this too didn't reflect the difference. I know I am making some minor mistake here.
But could some one help me getting my result?
Thanks a lot!
There's an easy way to get a full deepcopy of an NSDictionary o NSArray using the NSCoding (serialization) protocol.
- (id) deepCopy:(id)mutableObject
{
NSData *buffer = [NSKeyedArchiver archivedDataWithRootObject:mutableObject];
return [NSKeyedUnarchiver unarchiveObjectWithData: buffer];
}
In this way you can duplicate any object plus all the obects it contains in a single step.
when I need a mutable deep copy of a NSDictionary I create a Category with this method:
- (NSMutableDictionary *)mutableDeepCopy
{
NSMutableDictionary *returnDict = [[NSMutableDictionary alloc] initWithCapacity:[self count]];
NSArray *keys = [self allKeys];
for (id key in keys) {
id oneValue = [self valueForKey:key];
id oneCopy = nil;
if ([oneValue respondsToSelector:#selector(mutableDeepCopy)]) {
oneCopy = [oneValue mutableDeepCopy];
} else if ([oneValue respondsToSelector:#selector(mutableCopy)]) {
oneCopy = [oneValue mutableCopy];
}
if (oneCopy == nil) {
oneCopy = [oneValue copy];
}
[returnDict setValue:oneCopy forKey:key];
}
return returnDict;
}
EDIT
and searching the web I found this, I haven't tested
NSMutableDictionary *mutableCopy = (NSMutableDictionary *)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFDictionaryRef)originalDictionary, kCFPropertyListMutableContainers);

Saving bool property to file in iOS.

I want save bool property to my file, and I did it in my opinion is barbaric. I have to check my property and then add string to NSMutableArray. Can I some how check property name, state/value and then save to file? Or maybe I should use XML file for this? But still for efficient use I should get property name and state/value.
Could you give me some advice?
-(void) saveSettings
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"settings" ofType:#""];
if (music)
{
[correctSettingArray removeObjectAtIndex:0];
[correctSettingArray addObject:#"music = 1"];
}
else
{
[correctSettingArray removeObjectAtIndex:0];
[correctSettingArray addObject:#"music = 0"];
}
if (sfx)
{
[correctSettingArray removeObjectAtIndex:1];
[correctSettingArray addObject:#"sfx = 1"];
}
else
{
[correctSettingArray removeObjectAtIndex:0];
[correctSettingArray addObject:#"sfx = 0"];
}
if (vibration)
{
[correctSettingArray removeObjectAtIndex:0];
[correctSettingArray addObject:#"vibration = 1"];
}
else
{
[correctSettingArray removeObjectAtIndex:0];
[correctSettingArray addObject:#"vibration = 0"];
}
[correctSettingArray writeToFile:path atomically:true];
}
Thanks in Advance.
if you want to save simple application settings like this use NSUserDefaults
[[NSUserDefaults standardUserDefaults] setBool:vibrationBool forKey:#"vibrationKey"];
then when you want to read it
BOOL vibrationBool = [[NSUserDefaults standardUserDefaults] boolForKey:#"vibrationKey"];
I think you can save as NSNumber using this...
[NSNumber numberWithBool:BOOLATR]
and retrieve the value doing...
BOOLATR = [[correctSettingArray objectAtIndex:X] boolValue]
In any case, you could prefer to use NSMutableDictionary for variable matching instead an array.
[dictionary setValue:[NSNumber numberWithBool:BOOLATR] forKey:#"BOOLATR"];
&
BOOLATR = [[dictionary valueForKey:#"BOOLATR"] boolValue]
For what you ask — saving user settings — you should use NSUserDefaults as described in answer by wattson12.
If you really need to save boolean properties to file, given you are working with Objective-C objects, easiest way would be to use archive and serialize your data structure by implementing the NSCoding protocol. See Apple's Archives and Serializations Programming Guide.
The NSCoding protocol has two parts: initWithCoder is basically another constructor for your object:
- (id)initWithCoder:(NSCoder *)decoder
{
self = [super init];
if (self) {
if ([decoder containsValueForKey:#"sunNeverSet"])
self.sunNeverSet = [NSNumber numberWithBool:
[decoder decodeBoolForKey:#"sunNeverSet"]];
}
return self;
}
The encodeWithCoder is the serialization:
- (void)encodeWithCoder:(NSCoder *)coder
{
if (sunNeverRise) [coder encodeBool:[sunNeverRise boolValue]
forKey:#"sunNeverRise"];
}
Then you would encode your object graph into platform-independent byte stream (ie. NSData) using the NSKeyedArchiver and write the data to file.
NSMutableData *data = [[NSMutableData alloc] init];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]
initForWritingWithMutableData:data];
[archiver encodeRootObject:myObjectImplementingNSCoding];
[archiver finishEncoding];
[data writeToFile:path atomically:YES];
To read it back, you'll decode the data using NSKeyedUnarchiver and get back your object graph.
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc]
initForReadingWithData:data];
id myObjectImplementingNSCoding = [[unarchiver decodeObject] retain];
[unarchiver finishDecoding];

Populating NSDictionary and NSArrays for Model data

I'm trying to create an NSDictionary full of arrays in the implementation file of my model but my code hasn't worked yet. I want to create arrays that are lists of types of dogs and cats and then add those arrays to a dictionary with keys called DOG and CAT. Here is my code:
#implementation wordDictionary
#synthesize catList = _catList;
#synthesize dogList = _dogList;
#synthesize standardDictionary =_standardDictionary;
- (void)setCatList:(NSMutableArray *)catList
{
self.catList = [NSMutableArray arrayWithObjects:#"lion", #"puma", #"snow leopard", nil];
}
- (void)setDogList:(NSMutableArray *)dogList
{
self.dogList = [NSMutableArray arrayWithObjects:#"pit bull", #"pug", #"chihuahua", nil];
}
-(void)setStandardDictionary:(NSMutableDictionary *)standardDictionary
{
[self.standardDictionary setObject: _catList forKey:#"CAT"];
[self.standardDictionary setObject: _dogList forKey:#"DOG"];
}
- (NSString*)selectKey
{
NSInteger keyCount = [[self.standardDictionary allKeys] count];
NSInteger randomKeyIndex = arc4random() % keyCount;
NSString *randomKey = [[self.standardDictionary allKeys] objectAtIndex:randomKeyIndex];
return randomKey;
}
#end
This code is the model. The model is hooked up to my view controller such that when a user taps a button, the NSString returned from randomKey is displayed in a label on the screen. So the text will read either CAT or DOG. Here's the code for that:
- (IBAction)changeGreeting:(UIButton*)sender {
NSString *chosenKey = [self.dictionary selectKey];
NSString *labelText = [[NSString alloc] initWithFormat:#"%#", chosenKey];
self.label.text = labelText;
}
Unfortunately when I tap the button on the simulator I get an error message saying: Thread 1:EXC_ARITHMETIC (code=EXC_1386_DIV, subcode=0x0) at NSInteger randomKeyIndex = arc4random() % keyCount; and it appears that I'm getting it because neither my NSArray nor my NSDictionary have any objects inside of them.
Does anyone have any idea why my NSArray and NSDictionary haven't been populated?
Thanks very much.
The simple answer is that there isn't any code here that calls the methods to set the arrays or dictionary.
But the real underlying issue is that there are a couple of bad 'patterns' going on here that you should fix:
In your setter methods (setCatList:, setDogList:, setStandardDictionary:) you're not setting the properties in question to the values that are passed in. For example, you should be setting catList to the passed in "catList" variable.
- (void)setCatList:(NSMutableArray *)catList
{
if (_catList != catList) {
[_catList release];
_catList = [catList retain];
}
}
Then you should have some kind of "setup" happening, usually in a method in the view controller like viewDidLoad:
[wordDictionary setCatList:[NSMutableArray arrayWithObjects:#"lion", #"puma", #"snow leopard", nil]];
// and more for the other two setters
Alternately, you can set these default values in the init for the wordDictionary class:
- (id)init {
self = [super init];
if (self) {
[self setCatList:[NSMutableArray arrayWithObjects:#"lion", #"puma", #"snow leopard", nil]];
}
return self;
}
The former is better in most cases, but you may have a good reason to pre-populate your model for all instances of the class.
Assuming you called setCatList:, setDogList: and setStandardDictionary: before. Probably that causing is this :
NSString *chosenKey = [self.dictionary selectKey];
change into this :
NSString *chosenKey = [self selectKey];
UPDATE
I'm trying to make your life easier. no need to create your object if you don't need the most.
- (NSMutableArray*)getCatList
{
return [NSMutableArray arrayWithObjects:#"lion", #"puma", #"snow leopard", nil];
}
- (NSMutableArray*)getDogList
{
return [NSMutableArray arrayWithObjects:#"pit bull", #"pug", #"chihuahua", nil];
}
-(NSMutableDictionary*)getStandardDictionary
{
NSMutableDictionary *standardDictionary = [NSMutableDictionary new];
[standardDictionary setObject:[self getCatList] forKey:#"CAT"];
[standardDictionary setObject:[self getDogList] forKey:#"DOG"];
return [standardDictionary autorelease];
}
- (NSString*)selectKey
{
NSMutableDictionary *standardDictionary = [self getStandardDictionary];
NSInteger keyCount = [[standardDictionary allKeys] count];
NSInteger randomKeyIndex = arc4random() % keyCount;
NSString *randomKey = [[standardDictionary allKeys] objectAtIndex:randomKeyIndex];
return randomKey;
}
- (IBAction)changeGreeting:(UIButton*)sender {
// NSString *chosenKey = [self selectKey];
//NSString *labelText = [[NSString alloc] initWithFormat:#"%#", chosenKey];
self.label.text = [self selectKey]; //no need to convert it to NSString again
}
Two things to consider:
I don't see you calling these:
setCatList:(NSMutableArray*)catList;
setDogList:(NSMutableArray*)dogList;
You use self.catList and self.dogList, but neither of those are synthesized, instead you have beatList and meList synthesized
Change the synthesizes to the catList and dogList, and make sure you call the set list methods, and then you should make some progress.