i having a problem with my NSUserdefaults. When i type in the name in the textbox and click on the highscore the application will not response anything and the keypad will still be on the screen. When i tried to load the data, it say that the data for name is nil. The score that i have is 90. Can someone please tell me what is wrong with my coding.
Lots of thanks.
-(IBAction)savehighscore_button {
int i, ii = -1;
struct high_score {
NSString *name;
int highScore;
};
struct high_score structArray[10];
NSUserDefaults *userPreferences = [NSUserDefaults standardUserDefaults];
for (i=0; i<10; i++) {
if ([userPreferences stringForKey :[NSString stringWithFormat:#"highScoreNameEntry%d",i]]!=nil && [userPreferences stringForKey :[NSString stringWithFormat:#"highScoreEntry%d"]]!=nil) {
structArray[i].name= [userPreferences stringForKey:[NSString stringWithFormat:#"highScoreNameEntry%d",i]];
structArray[i].highScore = [userPreferences integerForKey:[NSString stringWithFormat:#"highScoreEntry%d",i]];
ii = i;
}
}
if (myScore >0) {
for (i==ii; i>=0; i--) {
if (myScore > structArray[i].highScore) {
if (i<9) {
structArray[i+1] = structArray[i];
structArray[i].name = nametextbox.text;
structArray[i].highScore = myScore;
if (i==ii && i<9) {
structArray[i+1].name = nametextbox.text;
structArray[i+1].highScore = myScore;
ii=i+i;
}
else if(i==ii && i<9) {
structArray[i+1].name = nametextbox.text;
structArray[i+1].highScore = myScore;
ii=i+1;
}
}
}
if (ii==-1 && myScore >0) {
structArray[0].name = nametextbox.text;
structArray[0].highScore = myScore;
ii=0;
}
for (i=0; i<=ii; i++) {
[userPreferences setObject:structArray[i].name forKey:[NSString stringWithFormat:#"highScoreNameEntry%d",i]];
[userPreferences setInteger:structArray[i].highScore forKey:[NSString stringWithFormat:#"highScoreEntry%d",i]];
}
}
}
}
Anything saved into user defaults must be of a standard PLIST-compliant class (NSArray, NSDictionary, NSNumber, NSString, NSDate, NSData, NSValue). If it's not one of those, it has to be archived as an NSData instance (and therefore be NSCoding compliant) or packed into an NSValue if it's compatible.
That said, you're making this far more difficult on yourself than you need to. Why not have an array (the high score descriptor container) of dictionaries (each is a descriptor for a high score) that hold a name (an NSString) and the score (an NSNumber)? Each dictionary describes a high score for a given name. You can then store the whole thing by using -setObject:yourArray forKey:#"HighScores".
Since you only get immutable copies back from NSUserDefaults, you'll want to ask for a -mutableCopy of the high scores array (don't forget to release it) when you want to modify things. Either replace a score or delete/add.
Using this approach, you don't have to resort to the (sorry for this) ghastly "string#" approach with a fixed number of scores. Your array will only contain the existing high scores. No waste and all 100% standard Cocoa classes that are fully PLIST'able with no extra work. This also lets you easily sort the array using sort descriptors (sorted by the key you used to store the score number in the dictionary).
Some basic code:
/* Build a fake high scores array */
NSMutableArray * highScores = [NSMutableArray array];
// Bob's score
NSDictionary * bob = [NSDictionary dictionaryWithObjectsAndKeys:
#"Bob", #"name",
[NSNumber numberWithInt:8234323], #"score",
nil];
[highScores addObject:bob];
// Jane's score
NSDictionary * jane = [NSDictionary dictionaryWithObjectsAndKeys:
#"Jane", #"name",
[NSNumber numberWithInt:92346345], #"score",
nil];
[highScores addObject:jane];
// Donald's score
NSDictionary * donald = [NSDictionary dictionaryWithObjectsAndKeys:
#"Donald", #"name",
[NSNumber numberWithInt:5272348], #"score",
nil];
[highScores addObject:donald];
// Sort by high score
NSSortDescriptor * sort = [[NSSortDescriptor alloc] initWithKey:#"score"
ascending:NO];
[highScores sortUsingDescriptors:[NSArray arrayWithObject:sort]];
[sort release];
// Store in user defaults
[[NSUserDefaults standardUserDefaults] setObject:highScores
forKey:#"HighScores"];
Dont forget to use:
[userPreferences synchronize];
Related
I have beeen storing some string values to an mutablearray to store in to a nsuserdefaults.like the way `
NSMutableArray *arrayObj = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:#"emoved"]];
for(int i = 0 ; i<[searcharray count]; i++)
{
NSLog(#"%#",searcharray);
NSDictionary *dictionarydate = [searcharray objectAtIndex:i];
NSString *memeid=[[dictionarydate objectForKey:#"ID"]description];
if([dictionarydate objectForKey:#"dateOfInfo"])
{
if ([arrayObj containsObject:memeid])
{
}
else
{
[arrayObj addObject:memeid];
}
}
}
[[NSUserDefaults standardUserDefaults] setObject:arrayObj forKey:#"emoved"];
` so when printng you need to add a value only at once .but when i am priting that value i am seing the same value is added to the array multiple times.is there anything wrong in my approach can anybody point out?
You should allocate and initialize your NSMutableArray like
NSMutableArray *arrayObj = [[NSMutableArray alloc] initWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:#"emoved"]];
If you aren't using ARC, don't forget to release your arrayObj right after you're done with it
for(Attribute* attribute in appDelegate.attributeArray) {
attribute = [appDelegate.attributeArray objectAtIndex:z];
attri = attribute.zName;
int y = 0;
for(Row* r in appDelegate.elementsArray) {
r = [appDelegate.elementsArray objectAtIndex:y];
NSString *ele = r.language;
if([attri isEqualToString:ele]) {
NSLog(#"=================+++++++++++++++++%# %#",attri, r.user);
[aaa insertObject:r atIndex:y]; //here i am adding the value to array
[dict setObject:aaa forKey:attri]; //here i am adding the array to dictionary
}
y++;
}
z++;
NSLog(#"============$$$$$$$$$$$$$$$$$$$$$$$++++++++++ %#",dict);
}
key in one array and the value in the another array and the value array is in object format.
I need to store the multi object for the single key. The attributeArray has the key value and the elementsArray has the object. For example the attributeArray might have the values
" English, French, German..."
and the elementsArray might have the object value
"<Row: 0x4b29d40>, <Row: 0x4b497a0>, <Row: 0x4e38940>, <Row: 0x4b2a070>, <Row: 0x4b29ab0>, <Row: 0x4b178a0> "
In the first value I need to store the two object and for second key I need to store 3 objects and for the third key in need to store last two objects in the dictionary.
For super-simplification you can use the following code:
NSArray *keys = ...;
NSArray *values = ...;
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjects: values forKeys: keys];
Hope, this helps.
UPDATE:
to store multiple values for single key in the dictionary, just use NSArray / NSMutableArray as your object:
NSArray *keys = ...;
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
for( id theKey in keys)
{
NSMutableArray *item = [NSMutableArray array];
[item addObject: ...];
[item addObject: ...];
...
[dict setObject: item forKey: theKey];
}
If you don't know all the values for the key from the beginning and need to add them one by one, you can use the following approach:
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
for( /*some cycling condition here */)
{
id keyToUse = ...;
id valueToAdd = ...;
id foundArray = [dict objectForKey: keyToUse];
if ( nil == foundArray )
{
foundArray = [NSMutableArray array];
[dict setObject: foundArray forKey: keyToUse];
}
[foundArray addObject: valueToAdd];
}
To me it looks you are settings an array (aaa) with string (attri) as a key.
To set an array as a key for another array as an object. You can do this with the following appraoch.
NSMutableDictionary *myDictionary = [NSMutableDictionary dictionaryWithCapacity:1];
NSArray *valueArray = [NSArray arrayWithObjects:#"v1", #"v2", nil];
NSArray *keyArray = [NSArray arrayWithObjects:#"k1",#"k2", nil];
[myDictionary setObject:valueArray forKey:keyArray];
NSLog(#"myDictionary: %#", myDictionary);
But you should review your code and provide a more brief explanation that what do you want to achieve and how are you taking an approach for this.
regards,
Arslan
I am writing a shopping cart application where I have Item Information sent back from server as a NSDictionary object with item number,description,price as values for their keys. I add all these Dictionary objects to mutable array and display in a table view. To manually increment quantity of each item I have added Quantity key to Item Dictionary object.
NSMutableDictionary* itemDictionary = [[NSMutableDictionary alloc] initWithDictionary:inventory.itemDict];
[itemDictionary setObject:[NSString stringWithFormat:#"1"] forKey:#"Quantity"];
[itemsArray addObject:itemDictionary];
[itemDictionary release];
[self.tableView reloadData];
How to increment value for key Quantity if there is a duplicate entry of the same item ? If I add same item to array I would end up with a duplicate, How to find duplicate item i.e., item that has same price, description and item number while ignoring value of Quantity key of the dictionary when searching for duplicates
I would create a new dict containing two items: the inventory dict and the quantity. I'd add an item to itemsArray like this (untested, so beware of typos):
BOOL found = NO;
for (NSDictionary *dict in itemsArray)
{
if ([[dict objectForKey: #"inventorydict"] isEqual: inventory.itemDict])
{
[dict setObject: [NSNumber numberWithInt:
[[dict objectForKey: #"quantity"] intValue] + 1]
forKey: #"quantity"];
found = YES;
break;
}
}
if (!found)
{
[itemsArray addObject:
[NSMutableDictionary dictionaryWithObjectsAndKeys:
inventory.itemDict, #"inventorydict",
[NSNumber numberWithInt: 1], #"quantity",
nil]];
}
So itemsArray contains NSDictionaries with two keys: "inventorydict" and "quantity". "inventorydict" is the dict passed to you containing the item the user bought, and "quantity" is an NSNumber. When you receive a new product item in the basket, you first check if the item is already in the array. If so, you add one to the "quantity" number, otherwise you create a new dictionary with the inventory item and a quantity of 1.
Store your dictionaries in an NSCountedSet. You can then get the quantity via -countForObject:. Use an array only for presentation purposes, so you can sort the values in a sane way. Rebuild this array whenever the set changes, something like so:
- (void)itemsDidChange
{
NSCountedSet *itemSet = [self itemSet];
NSMutableArray *sortedItems = [[NSMutableArray alloc] init];
for (NSDictionary *item in itemSet) {
NSUInteger count = [itemSet countForObject:item];
NSNumber *countNum = [[NSNumber alloc] initWithUnsignedInteger:count];
NSMutableDictionary *arrayItem = [item mutableCopy];
[arrayItem setObject:countNum forKey:KEY_QUANTITY];
[countNum release];
[sortedItems addObject:arrayItem];
[arrayItem release];
}
[sortedItems sortUsingComparator:/* your comparator here */];
[self setRowItems:sortedItems];
[[self tableView] reloadData];
}
Even simpler, use the object directly in your array without changing it at all. When you present the quantity to the user in the UI, just query the itemSet for the count, and use that. The array is then used solely to impose an order on the set's items.
FYI for setObject: you do not need to use stringWithFormat: if you do not have an object to add to it, you can simply use setObject:#"1".
If you want to increment the Quantity, you should be using setObject:[NSNumber numberWithInt:1] instead.
based on Rudy's post made it working this way:
-(void)addToCart:(id)sender
{
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
BOOL found = NO;
NSString *itemName = // get your item name here
[theDict setObject:itemName forKey:#"name"];
if ([appDelegate.theCartArray isEqual:nil])
{
[appDelegate.theCartArray addObject:theDict];
}
else //implementing Rudy's idea
{
for (theDict in appDelegate.theCartArray)
{
if ([[theDict objectForKey:#"name"] isEqual:itemName])
{
[theDict setObject: [NSNumber numberWithInt:
[[theDict objectForKey: #"quantity"] intValue] + 1]
forKey: #"quantity"];
found = YES;
break;
}
}
if (!found)
{
[appDelegate.theCartArray addObject:
[NSMutableDictionary dictionaryWithObjectsAndKeys:
itemName, #"name",
[NSNumber numberWithInt: 1], #"quantity",
nil]];
}
}
}
I am trying to figure out the best approach for queries on a plist. Thus, attempting at making an sql equivalent to "SELECT * FROM sometable WHERE somecol = someval AND someothercol = someotherval AND ".... so on and soforth ... using a plist as the sql table equivalent. Coming from Ruby and mysql, this just seems like a lot of code for one simply query. The results come back as expected (at least at first run they did, I have not tested this rigorously) with no errors.
So here is the question: Is there some simple method hiding in the docs somewhere that would make this less clunky?
and if not what is a better approach?
EPFramework.m
// LOAD PLIST AND FILTER MULTIPLE TIMES
-(NSMutableArray *)loadPlistAndFilterMultipleTimes:(NSString *)plist ArrayOfKeys:(NSArray *)arrayOfKeys ArrayOfKeyValues:(NSArray *)arrayOfKeyValues
{
// set the array counts
int arrayOfKeysCount = [arrayOfKeys count];
int arrayOfKeyValuesCount = [arrayOfKeyValues count];
// initialize the array to return
NSMutableArray *arrayFilteredResults = [[[NSMutableArray alloc] init] retain];
// qualify the search
if(arrayOfKeysCount == arrayOfKeyValuesCount && arrayOfKeysCount > 0 && arrayOfKeyValuesCount > 0)
{
// get the plist
NSString *fullFileName = [NSString stringWithFormat:#"%#.plist", plist];
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:fullFileName];
// put the plist records into an array
NSArray *arrayOfDictionaryItemsInPlist = [[NSMutableArray alloc] initWithContentsOfFile:path];
// load our dynamic array for mutability throughout the loops
NSMutableArray *arrayFiltered = [[[NSMutableArray alloc] initWithArray:arrayOfDictionaryItemsInPlist] retain];
// build an array of the final results to return
for(int i=0; i < arrayOfKeysCount; i ++)
{
// initialize this loops search criteria
NSString *key = [arrayOfKeys objectAtIndex:i];
id value = [arrayOfKeyValues objectAtIndex:i];
// set the filter
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K == %#", key, value];
// filter the result
arrayFilteredResults = [[[NSArray alloc] initWithArray:[arrayFiltered filteredArrayUsingPredicate:predicate]] retain];
}
} else {
NSLog(#"arrOfKeys count does not match arrayOfKeyValues count"); // the search did not qualify
}
// return the results
return arrayFilteredResults;
// release the allocated memory
[arrayFilteredResults release];
}
IndexController.m
NSArray *arrayOfKeys = [NSArray arrayWithObjects:
[NSString stringWithString:#"recordset"],
[NSString stringWithString:#"ep_object_attribute_id"],
nil];
NSArray *arrayOfKeyValues = [NSArray arrayWithObjects:
[NSString stringWithString:#"1778587279"],
[NSNumber numberWithInt:133],
nil];
NSMutableArray *arrayOfResult = [epFrameWork loadPlistAndFilterMultipleTimes:#"FormEntries" ArrayOfKeys:arrayOfKeys ArrayOfKeyValues:arrayOfKeyValues];
NSLog(#"arrayOfResult: %#", arrayOfResult);
Here's the link for fmdb. Should be quick to pick it up, be faster and you get a real database instead of simulating one with plists :)
https://github.com/ccgus/fmdb
Hope that helps
I need to sort a NSDictionary of dictionaries. It looks like:
{//dictionary
RU = "110.1"; //key and value
SG = "150.2"; //key and value
US = "50.3"; //key and value
}
Result need to be like:
{//dictionary
SG = "150.2"; //key and value
RU = "110.1"; //key and value
US = "50.3"; //key and value
}
I am trying this:
#implementation NSMutableDictionary (sorting)
-(NSMutableDictionary*)sortDictionary
{
NSArray *allKeys = [self allKeys];
NSMutableArray *allValues = [NSMutableArray array];
NSMutableArray *sortValues= [NSMutableArray array];
NSMutableArray *sortKeys= [NSMutableArray array];
for(int i=0;i<[[self allValues] count];i++)
{
[allValues addObject:[NSNumber numberWithFloat:[[[self allValues] objectAtIndex:i] floatValue]]];
}
[sortValues addObjectsFromArray:allValues];
[sortKeys addObjectsFromArray:[self allKeys]];
[sortValues sortUsingDescriptors:[NSArray arrayWithObject:[[[NSSortDescriptor alloc] initWithKey:#"floatValue" ascending:NO] autorelease]]];
for(int i=0;i<[sortValues count];i++)
{
[sortKeys replaceObjectAtIndex:i withObject:[allKeys objectAtIndex:[allValues indexOfObject:[sortValues objectAtIndex:i]]]];
[allValues replaceObjectAtIndex:[allValues indexOfObject:[sortValues objectAtIndex:i]] withObject:[NSNull null]];
}
NSLog(#"%#", sortKeys);
NSLog(#"%#", sortValues);
NSLog(#"%#", [NSMutableDictionary dictionaryWithObjects:sortValues forKeys:sortKeys]);
return [NSMutableDictionary dictionaryWithObjects:sortValues forKeys:sortKeys];
}
#end
This is the result of NSLog:
1)
{
SG,
RU,
US
}
2)
{
150.2,
110.1,
50.3
}
3)
{
RU = "110.1";
SG = "150.2";
US = "50.3";
}
Why is this happening? Can you help me with this problem?
NSDictionary are unsorted by nature. The order of the objects as retrieved by allKeys and allValues will always be undetermined. Even if you reverse engineer the order it may still change in the next system update.
There is however more powerful alternatives to allKeys that are used to retrieve the keys in a defined and predictable order:
keysSortedByValueUsingSelector: - Useful for sorting in ascending order according to the compare: method of the value objects.
keysSortedByValueUsingComparator: - New in iOS 4, use a block to do the sort inline.
WOW. Thanx, PeyloW! It's what i needed! I also find this code and it helps me to reorder results:
#implementation NSString (numericComparison)
- (NSComparisonResult) floatCompare:(NSString *) other
{
float myValue = [self floatValue];
float otherValue = [other floatValue];
if (myValue == otherValue) return NSOrderedSame;
return (myValue < otherValue ? NSOrderedAscending : NSOrderedDescending);
}
- (NSComparisonResult) intCompare:(NSString *) other
{
int myValue = [self intValue];
int otherValue = [other intValue];
if (myValue == otherValue) return NSOrderedSame;
return (myValue < otherValue ? NSOrderedAscending : NSOrderedDescending);
}
#end
a NSDictionary is not ordened, so it doens't matter in what order you construct a NSDIctionary.
a NSArray is ordened. If you want to have the NSDictionary ordened in memory, you should somehow make a NSArray of key value pairs. You can also return two NSArrays with corresponding indeces.
If you only want to iterate over the elements way, you can iterate over a sorted array of keys (this is what koregan suggests).