Hello I am trying to save and load my game data. It cannot read an integer properly from a file, however it can read a string properly though...
Strangely enough when I print the number with NSLog it works!. However if I try to use the value or pass it into another value it doesn't.
Now I could 'fix' this by converting all the numbers into strings and then saving it, then loading the strings and converting it back to numbers. However I would like to know the proper way of doing it. Also there are 1600 tiles not including other data so that would be a noticeable overhead.
Can someone tell me what I am doing wrong or what NSLog is doing automatically?
Below is the code section relevant to the question. mapData[i][j] is an array of integers representing whats on a tile.
-(void)saveGame
{
NSLog(#"%s", "Saved");
NSString *temp = [self saveFilePath];
NSLog(#"%s %#", "FilePath", temp);
NSMutableArray *values = [NSMutableArray arrayWithCapacity:1602];
int i = 0;
int j = 0;
int a = 0;
for(i = 0; i < 40; i++)
{
for(j = 0; j < 40; j++)
{
//values[i] = mapData[j][k];
[values addObject:[NSNumber numberWithInteger:mapData[i][j]]];
NSLog(#"%d, %d", i, j);
NSLog(#"%s, %d", "Map Data: ", mapData[i][j]);
NSLog(#"%#", [values objectAtIndex:a]);
a++;
}
}
// test letter OK
NSString * letterA = #"a";
[values addObject:[NSString stringWithString:letterA]];
// test independant number
NSInteger aNum = 888;
[values addObject:[NSNumber numberWithInteger:aNum]];
NSArray *value = [NSArray arrayWithArray:values];
// test conversion OK
a = 0;
for(i = 0; i < 40; i++)
{
for(j = 0; j < 40; j++)
{
NSLog(#"%#", [value objectAtIndex:a]);
a++;
}
}
NSLog(#"%#", [value objectAtIndex:a]); // letter OK
a++;
NSLog(#"%#", [value objectAtIndex:a]); // number OK
[value writeToFile:[self saveFilePath] atomically:YES]; // atomically means all or nothing. i.e power fail will not save half
}
-(NSString *)saveFilePath
{
NSArray * path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
return [[path objectAtIndex:0] stringByAppendingPathComponent:#"savefile.plist"];
}
-(void)loadGame
{
NSLog(#"%s", "Loaded");
NSString *loadPath = [self saveFilePath];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:loadPath];
if(fileExists)
{
NSArray *values = [[NSArray alloc] initWithContentsOfFile:loadPath];
int a = 0;
for(int i = 0; i < 40; i++)
{
for(int j = 0; j < 40; j++)
{
//mapData[i][j] = [values objectAtIndex:a];
//mapData[i][j] = (NSInteger)[values objectAtIndex:a];
NSInteger * tempNumber = [values objectAtIndex:a];
NSLog(#"%#", tempNumber); // YES!
int tempInt = (int)tempNumber;
NSLog(#"%d", tempInt); // no
mapData[i][j] = tempNumber;
NSLog(#"%d, %d, %d", a , i, j);
NSLog(#"%s, %d", "Loaded Map Data: ", mapData[i][j]); // no
a++;
}
}
// string works but integer doesnt...
NSString * letter;
letter = [values objectAtIndex:a];
NSLog(#"%#", letter); // YES
// this number OK - needs pointer AND NSLog...
a++;
NSInteger * number;
number = [values objectAtIndex:a];
NSLog(#"%#", number); // YES
}
}
Nvm I figured it out. NSLog was automatically unwrapping the numbers for me. Manually unwrapping will display the correct numbers instead of memory addresses.
Related
The user enters a value between 0 and 5000 into a text box. My need is to replace bytes 4 and 5 in dataToSend with the hex value in the text box. For example, if the user enters 250 I translate that into 00FA. In dataToSend, replace 0x03 with 0x00 and 0xEB with 0xFA. str and str2 are there so I can see the data. There is a difference between them, and I don't know which is correct.
- (IBAction)handleConfig1DelayMoveChange:(id)sender
{
NSString *tmp;
int value;
tmp = [txtDelayBeforeMove1 stringValue];
NSString *hex = [NSString stringWithFormat:#"0x%04lX",(unsigned long)[tmp integerValue]];
NSString *hex1 = [NSString stringWithFormat:#"%04lX",(unsigned long)[tmp integerValue]];
dataToSend = [NSMutableData dataWithBytes:&((char[6]){0x51,0x04,0x02,0x03,0xEB,0x0D}) length:6];
NSString *str = [[NSString alloc] initWithData:dataToSend encoding:NSASCIIStringEncoding];
NSString *str2 = [NSString stringWithFormat:#"%.*s", [dataToSend length], [dataToSend bytes]];
tmp = #"";
tmp = [hex1 substringWithRange:NSMakeRange(1,2)];
value = [tmp intValue];
[dataToSend replaceBytesInRange: NSMakeRange(3,1) withBytes: &value];
str2 = [NSString stringWithFormat:#"%.*s", [dataToSend length], [dataToSend bytes]];
}
This works. Comments and suggestions for improvement are welcome. displayhexStr was used to verify changes while debugging.
- (IBAction)handleConfig1DelayMoveChange:(id)sender
{
NSString *tmp;
int i;
if([txtDelayBeforeMove1 intValue] < 0 || [txtDelayBeforeMove1 intValue] > 5000)
{
[self showAlert:#"Value must be between 0 and 5000"];
return;
}
tmp = [txtDelayBeforeMove1 stringValue];
NSString *hex1 = [NSString stringWithFormat:#"%04lX",(unsigned long)[tmp integerValue]];
dataToSend = [NSMutableData dataWithBytes:&((char[6]){0x51,0x04,0x02,0x03,0xEB,0x0D}) length:6];
NSMutableString *displayhexStr =
[NSMutableString stringWithCapacity:[dataToSend length]*2];
for (i = 0; i < [dataToSend length]; i++) {
[displayhexStr appendFormat:#"%02x ", dbytes[i]];
}
tmp = [hex1 substringWithRange:NSMakeRange(0,2)];
NSScanner* scanner = [NSScanner scannerWithString:tmp];
unsigned int intValue;
[scanner scanHexInt:&intValue];
unsigned char uc = (unsigned char) intValue;
[dataToSend replaceBytesInRange: NSMakeRange(3,1) withBytes: &uc];
displayhexStr = [NSMutableString stringWithCapacity:[dataToSend length]*2];
for (i = 0; i < [dataToSend length]; i++)
{
[displayhexStr appendFormat:#"%02X ", dbytes[i]];
}
tmp = [hex1 substringWithRange:NSMakeRange(2,2)];
scanner = [NSScanner scannerWithString:tmp];
[scanner scanHexInt:&intValue];
uc = (unsigned char) intValue;
[dataToSend replaceBytesInRange: NSMakeRange(4,1) withBytes: &uc];
displayhexStr = [NSMutableString stringWithCapacity:[dataToSend length]*2];
for (i = 0; i < [dataToSend length]; i++)
{
[displayhexStr appendFormat:#"%02X ", dbytes[i]];
}
[self send];
}
The code below takes a string, adds each letter to an array and shuffles that array and shows the end result in a label. That works well. But I'd like for each character to contain a single character of the shuffled string. Right now it almost works, but it always repeats the characters. Like instead of having a series of 6 buttons with their titles: L e a g u e, the code generates repeated characters like: Leaauu.
My code is this:
- (IBAction)shuffleButttonTitles:(id)sender {
// The mutable array must be created here to create a new instance each time the button is tapped
letters = [[NSMutableArray alloc] init];
str = #"League";
length = str.length;
NSString *letter;
UIButton *button;
// First loop through the string and add each letter to an array
for (int i = 0; i < length; i++) {
letter = [NSString stringWithFormat:#"%c", [str characterAtIndex:i]];
[letters addObject:letter];
}
// Shuffle the string for the label/buttons
for (int i = 0; i < length; i++) {
int value = arc4random() % (length - 1);
[letters exchangeObjectAtIndex:i withObjectAtIndex:value];
//Create the button and shuffle the letters for their titles
button = [[UIButton alloc] initWithFrame:CGRectMake(50 * i, 350, 44, 44)];
// HERE THE CODE REPEATS THE CHARACTERS
[button setTitle:[letters objectAtIndex:i] forState:UIControlStateNormal];
//Store the button in our array
[myButtons addObject:button];
NSLog(#"Letters in Array: %lu", letters.count);
}
for (UIButton *button in myButtons){
[button setBackgroundColor:[UIColor redColor]];
[self.view addSubview:button];
}
// Now we set the randomized title to the label
NSString *results = [letters componentsJoinedByString:#""];
string.text = results;
}
After some searching on the web I've figured it out. I post the complete code for others. This code takes a random string from the Characters.txt file and shuffles that string. Then it rotates the tiles slighty. You can enter the correct word when you have figured out the anagram, which then shows an alert view if you got it or didn't get it.
#define kTileSpacing 20
#define randomf(minX,maxX) ((float)(arc4random() % (maxX - minX + 1)) + (float)minX)
#interface ViewController ()
#end
#implementation ViewController
{
}
#synthesize progressView;
- (void)viewDidLoad {
[super viewDidLoad];
NSString *path = [[NSBundle mainBundle] pathForResource:#"Anagrams" ofType:#"plist"];
dictionary = [[NSMutableArray alloc] initWithContentsOfFile:path];
NSString *quotesFile = [[NSBundle mainBundle] pathForResource:#"Characters" ofType:#"txt"];
fileContents = [NSString stringWithContentsOfFile:quotesFile encoding:NSUTF8StringEncoding error:NULL];
// [txtField becomeFirstResponder];
//[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(checkWord:) name:nil object:nil];
}
- (IBAction)clear:(id)sender {
quoteArray = [fileContents componentsSeparatedByString:#"\n"];
NSString *quoteToDisplay;
currentQuestion = arc4random() % quoteArray.count;
quoteToDisplay = [quoteArray objectAtIndex: currentQuestion];
welldone.text = quoteToDisplay;
txtField.text = nil;
[txtField becomeFirstResponder];
for (UILabel *lbl in myButtons) {
[lbl removeFromSuperview];
}
}
- (IBAction)ShuffleString:(id)sender {
[self clear:nil];
// The mutable array must be created here to create a new instance each time the button is tapped
charactersArray = [[NSMutableArray alloc] init];
indexArray = [[NSMutableArray alloc] init];
myButtons = [[NSMutableArray alloc] init];
// 1. Shuffle the plist with the words to form anagrams from
currentQuestion = arc4random() % quoteArray.count;
str = [quoteArray objectAtIndex: currentQuestion]; //[[dictionary objectAtIndex:currentQuestion] objectForKey:#"Anagram"];
length = str.length;
NSString *letter;
// 2. Loop throught the chosen word and break it down into its letters and add them to an array
for (int i = 0; i < str.length; i++) {
// [charactersArray removeObjectAtIndex:i];
letter = [NSString stringWithFormat:#"%c", [str characterAtIndex:i]];
[charactersArray addObject:letter];
// NSLog(#"Number of letters: %#", charactersArray);
}
while ([charactersArray count]) {
int randomizing = arc4random() % [charactersArray count];
[indexArray addObject:[charactersArray objectAtIndex:randomizing]];
[charactersArray removeObjectAtIndex:randomizing];
// NSLog(#"NO REPEAT SHUFFLE: %lu", (unsigned long)indexArray.count);
}
/***************/
CGFloat staticY = self.view.bounds.size.height / 9 * 1; // Static X for all buttons.
CGFloat staticWidth = 46; // Static Width for all Buttons.
CGFloat staticHeight = 46; // Static Height for all buttons.
CGFloat staticPadding = 10; // Padding to add between each button.
float tileSize = ceilf( self.view.bounds.size.width / str.length );
NSLog(#"size %f", tileSize);
CGFloat xOffset = (self.view.bounds.size.width - str.length * (44+staticPadding));
NSLog(#"xOffset %f", tileSize);
xOffset = tileSize/ 2;
for (int i = 0; i < str.length; i++) {
singleCharacterLabel = [[UILabel alloc] init];
singleCharacterLabel.textAlignment = NSTextAlignmentCenter;
singleCharacterLabel.font = [UIFont fontWithName:#"Verdana-Bold" size:21];
singleCharacterLabel.frame = CGRectMake((staticPadding + (i * (staticHeight + staticPadding))), staticY, staticWidth, staticHeight);
// NSLog(#"X: %f", (staticPadding + (i * (staticHeight + staticPadding))));
//singleCharacterLabel.center = CGPointMake(i * 50 + self.view.bounds.origin.x + self.view.bounds.size.width /3, 80); // i * int +self... int = space between labels. Here it is '50'
// singleCharacterLabel.center = CGPointMake(self.view.bounds.size.width * i, self.view.bounds.size.height / 5 * 1); // 1/4th down from the top
singleCharacterLabel.layer.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"Tile.png"]].CGColor;
NSString *anagramString = [indexArray objectAtIndex:i];
singleCharacterLabel.text = anagramString;
[myButtons addObject:singleCharacterLabel];
//1
//set random rotation of the tile
//anywhere between -0.2 and 0.3 radians
float rotation = randomf(0,50) / (float)100 - 0.2;
singleCharacterLabel.transform = CGAffineTransformMakeRotation( rotation );
//2
//move randomly upwards
int yOffset = (arc4random() % 10) - 10;
singleCharacterLabel.center = CGPointMake(singleCharacterLabel.center.x, singleCharacterLabel.center.y + yOffset);
[self.view addSubview:singleCharacterLabel];
//NSLog(#"LOOP: %#", anagramString);
}
}
- (IBAction)checkWord:(id)sender {
if (([txtField.text isEqual:str])) {
alertCorrect = [[UIAlertView alloc] initWithTitle:#"" message:#"Well done!" delegate:self cancelButtonTitle:nil otherButtonTitles:#"Next", nil];
[alertCorrect show];
} else {
alertWrong = [[UIAlertView alloc] initWithTitle:#"" message:#"Sorry, try again." delegate:self cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
[alertWrong show];
}
// NSLog(#"String is: %lu", str.length);
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (alertView == alertCorrect) {
if (buttonIndex == 0) {
[self ShuffleString:nil];
NSLog(#"next");
}
}
if (alertView == alertWrong) {
if (buttonIndex == 1) {
// Wrong answer. Close view and let user try again
}
}
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (txtField.text.length == length) {
[self checkWord:nil];
NSLog(#"You entered %lu characters", length);
}
return YES;
}
I have a NSMutableArray *dataArray containing NSDictionaries. I want to iterate through the array in order to create a new NSMutableArray *tempDataArray with objects from the first array if the searchString matches one of the dictionaries values.
Here is my code:
self.tempDataArray = [[NSMutableArray alloc] init];
for (int i = 0; i < kDelegate.dataArray.count; i++) {
NSDictionary *dict = [kDelegate.dataArray objectAtIndex:i];
for (int j = 0; j < [dict allValues].count ; j++) {
if ([[[[dict allValues] objectAtIndex:j]stringValue] isEqualToString:searchString]) {
[self.tempDataArray addObject:dict];
}
}
}
Now this doesn't work because the dictionary also contains a NSDate. At least that is what I am reading from the error message:
-[__NSTaggedDate stringValue]: unrecognized selector sent to instance 0x41b7809e2600000d
Which I dont understand, because I do declare all the values as stringValue.
That was the first part of my problem. The second half is that this only searches for an exact match but I would rather have a search determining if the dictionaries values contain a substring.
Anyway, thanks for all your help!
(untested):
self.tempDataArray = [[NSMutableArray alloc] init];
for (NSUInteger i = 0; i < kDelegate.dataArray.count; i++) {
NSDictionary *dict = [kDelegate.dataArray objectAtIndex:i];
NSArray *allValues = [dict allValues];
for (NSUInteger j = 0; j < allValues.count; j++) {
NSObject *obj = [allValues objectAtIndex:j];
if ([obj isKindOfClass:[NSString class]]) {
NSRange range = [(NSString *)obj rangeOfString:searchString];
if (range.location != NSNotFound) {
[self.tempDataArray addObject:dict];
}
}
}
}
Can anyone show me how to sort an array(NSMutableArray) of NSDate in order for the actual dates?
Thanks!
I believe you want to use something like -NSMutableArray sortUsingSelector: and pass in #selector(compare:). Ie, assuming you had an NSMutableArray of NSDates named *dateArray*:
[dateArray sortUsingSelector:#selector(compare:)];
Here you go just modify some part of code for your requirement
- (NSArray *)sortedWeightEntriesByWeightDate:(NSArray *)unsortedArray {
NSMutableArray *tempArray = [NSMutableArray array];
NSMutableArray *sortedArray = [NSMutableArray arrayWithCapacity:0];
#try {
for(int i = 0; i < [unsortedArray count];i++) {
NSDateFormatter *df = [[NSDateFormatter alloc]init];
MyDataModal *entry = [unsortedArray objectAtIndex:i];
[df setDateFormat:#"yyyy-MM-dd"];
NSDate *date = [df dateFromString:entry.weightDate];
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
if(date) {
[dict setObject:entry forKey:#"entity"];
[dict setObject:date forKey:#"date"];
[tempArray addObject:dict];
}
[df release];
}
NSInteger counter = [tempArray count];
NSDate *compareDate;
NSInteger index;
for(int i = 0 ; i < counter; i++) {
index = i;
compareDate = [[tempArray objectAtIndex:i] valueForKey:#"date"];
NSDate *compareDateSecond;
for(int j = i+1 ; j < counter; j++) {
compareDateSecond=[[tempArray objectAtIndex:j] valueForKey:#"date"];
NSComparisonResult result = [compareDate compare:compareDateSecond];
if(result == NSOrderedDescending) {
compareDate = compareDateSecond;
index=j;
}
}
if(i!=index)
[tempArray exchangeObjectAtIndex:i withObjectAtIndex:index];
}
NSInteger counterIndex = [tempArray count];
for(int i = 0; i < counterIndex ; i++) {
[sortedArray addObject:[[tempArray objectAtIndex:i] valueForKey:#"entity"]];
}
}
#catch (NSException * e) {
NSLog(#"An exception occured while sorting weight entries by date");
}
#finally {
return [NSArray arrayWithArray:sortedArray];
}
}
Can we convert an NSArray to a C array?
If not what alternatives, are there? Suppose I need to feed the C array to OpenGL functions where the C array contains vertex pointers read from plist files.
The answer depends on the nature of the C-array.
If you need to populate an array of primitive values and of known length, you could do something like this:
NSArray* nsArray = [NSArray arrayWithObjects:[NSNumber numberWithInt:1],
[NSNumber numberWithInt:2],
nil];
int cArray[2];
// Fill C-array with ints
int count = [nsArray count];
for (int i = 0; i < count; ++i) {
cArray[i] = [[nsArray objectAtIndex:i] intValue];
}
// Do stuff with the C-array
NSLog(#"%d %d", cArray[0], cArray[1]);
Here's an example where we want to create a new C-array from an NSArray, keeping the array items as Obj-C objects:
NSArray* nsArray = [NSArray arrayWithObjects:#"First", #"Second", nil];
// Make a C-array
int count = [nsArray count];
NSString** cArray = malloc(sizeof(NSString*) * count);
for (int i = 0; i < count; ++i) {
cArray[i] = [nsArray objectAtIndex:i];
[cArray[i] retain]; // C-arrays don't automatically retain contents
}
// Do stuff with the C-array
for (int i = 0; i < count; ++i) {
NSLog(cArray[i]);
}
// Free the C-array's memory
for (int i = 0; i < count; ++i) {
[cArray[i] release];
}
free(cArray);
Or, you might want to nil-terminate the array instead of passing its length around:
// Make a nil-terminated C-array
int count = [nsArray count];
NSString** cArray = malloc(sizeof(NSString*) * (count + 1));
for (int i = 0; i < count; ++i) {
cArray[i] = [nsArray objectAtIndex:i];
[cArray[i] retain]; // C-arrays don't automatically retain contents
}
cArray[count] = nil;
// Do stuff with the C-array
for (NSString** item = cArray; *item; ++item) {
NSLog(*item);
}
// Free the C-array's memory
for (NSString** item = cArray; *item; ++item) {
[*item release];
}
free(cArray);
NSArray has a -getObjects:range: method for creating a C-array for a subrange of an array.
Example:
NSArray *someArray = /* .... */;
NSRange copyRange = NSMakeRange(0, [someArray count]);
id *cArray = malloc(sizeof(id *) * copyRange.length);
[someArray getObjects:cArray range:copyRange];
/* use cArray somewhere */
free(cArray);
I would suggest to convert yourself, with something like:
NSArray * myArray;
... // code feeding myArray
id table[ [myArray count] ];
int i = 0;
for (id item in myArray)
{
table[i++] = item;
}