EXC_BAD_ACESS error - objective-c

I get that error EXC_BAD_ACESS at the following line:
NSString *titleVarName = [[NSString alloc] initWithFormat:#"%#%#",#"occasionTitle",i];
Here is the for loop where the above code line is located:
for (i=0; i < count; ++i)
{
//Save the occasionS details to NSUserDefaults
NSString *titleVarName = [[NSString alloc] initWithFormat:#"%#%#",#"occasionTitle",i];
NSString *dateVarName = [[NSString alloc] initWithFormat:#"%#%#",#"occasionDate",i];
NSString *imageVarName = [[NSString alloc] initWithFormat:#"%#%#",#"occasionImage",i];
[[NSUserDefaults standardUserDefaults] setValue:[[[self displayedObjects] objectAtIndex:i]
title] forKey:titleVarName];
[[NSUserDefaults standardUserDefaults] setValue:[[[self displayedObjects] objectAtIndex:i]
date] forKey:dateVarName];
[[NSUserDefaults standardUserDefaults] setValue:[[[self displayedObjects] objectAtIndex:i]
imagePath] forKey:imageVarName];
//release
[titleVarName release];
[dateVarName release];
[imageVarName release];
[self dismissModalViewControllerAnimated:YES];
}
Isn't ok to alloc objects and release them inside a for loop?

You need to use %d or %i specifier instead of %# to specify an integer. If %# is used with int then it will try to access the object at the address specified by the int. For example, if the value of i is one then it is trying to access the object at address one which will cause a bad access.
NSString *titleVarName = [[NSString alloc] initWithFormat:#"%#%d",#"occasionTitle",i];
And also you don't need alloc and release here, though that is not the reason of bad access. You can use a convenience constructor.
NSString *titleVarName = [NSString stringWithFormat:#"occasionTitle%d", i];
// release not required
Do the same for dateVarName and imageVarName too.

Assuming i is an int, that line should be
NSString *titleVarName = [[NSString alloc] initWithFormat:#"%#%i",#"occasionTitle",i];
%# is used for Cocoa objects, not primitives like an int, float or bool;

Use the %# format specifier only for NSObject objects.
As i is an integer in your code, you have to use %d or %i for integers.
Moreover, there is no need to include the string using %#, you can use the static string directly in your format string:
NSString *titleVarName = [[NSString alloc] initWithFormat:#"occasionTitle%i",i];

Related

Get string from NSArray, saved using NSUserDefaults

I'm trying to save 2 strings into an array using NSUserDefaults, but when I want to get the strings there are some problems.
This is my code:
- (IBAction)closeSettingsView:(id)sender {
NSArray *saveStrings = [[NSArray alloc] initWithObjects:#"%#", #"%#", yourNameTextField.text, customPhraseTextField.text, nil];
NSUserDefaults *defaultsFields = [NSUserDefaults standardUserDefaults];
[defaultsFields setObject:saveStrings forKey:#"savedStrings"];
[defaultsFields synchronize];
}
- (void)viewDidLoad {
NSUserDefaults *defaultsFields = [NSUserDefaults standardUserDefaults];
NSArray *loadStrings = [defaultsFields stringArrayForKey:#"savedStrings"];
NSString *nameString = [NSString stringWithFormat:#"%#", [loadStrings objectAtIndex:0]];
NSString *phraseString = [NSString stringWithFormat:#"%#", [loadStrings objectAtIndex:1]];
NSLog(#"%#", nameString);
NSLog(#"%#", phraseString);
}
This is my log:
2013-07-09 02:59:31.639 Alarm Pro[219:60b] %#
2013-07-09 02:59:31.642 Alarm Pro[219:60b] %#
What can I do to correctly read the strings?
Instead of adding the #"%#" strings twice at the beginning of the array with:
NSArray *saveStrings = [[NSArray alloc] initWithObjects:#"%#", #"%#", yourNameTextField.text, customPhraseTextField.text, nil];
Insert just the variables with:
NSArray *saveStrings = [[NSArray alloc] initWithObjects:yourNameTextField.text, customPhraseTextField.text, nil];
With the code you have, the array has 4 objects, the first and second of which are the strings #"%#" and #"%#" again. Thus, when you call [loadStrings objectAtIndex:0] and [loadStrings objectAtIndex:1], the output is those first two strings, #"%#" and #"%#".
In other words, you're not first defining the formats of the objects and then passing the variables containing the strings with initWithObjects: but rather just the objects themselves, with no preceding formats.
Your strings are read correctly, it's just you're saving the wrong data.
NSArray *saveStrings = [[NSArray alloc] initWithObjects:#"%#", #"%#", yourNameTextField.text, customPhraseTextField.text, nil];
This creates an array with 4 elements. First two of them are #"%#", so when you take objectAtIndex 0 and 1, it correctly returns #"%#" in both cases.
You need to rewrite your save code a little:
NSArray *saveStrings = [[NSArray alloc] initWithObjects:yourNameTextField.text, customPhraseTextField.text, nil];
NSString *str1=[textbox1.text];
NSString *str2=[textbox2.text];
NSArray *arr=[[NSArray alloc]initWithObjects:str1,str2, nil];
then use NSUserDefaults
The other responses are correct.
You can also use the new Obj-C syntax to make it more readable.
NSArray *saveStrings = #[yourNameTextField.text, customPhraseTextField.text];
If you do want to actually format the string, I would split it on multiple lines. i.e.:
NSString *entry1 = [NSString stringWithFormat:#"Sir %#", yourNameTextField.text];
NSArray *saveStrings = #[entry1, customPhraseTextField.text];

How to view the entire content of an array in a label (xcode 4.1)

i'm programming in Obj-c with xcode4.1, i have an array with numbers in it, and i want to visualize all of them in a label...can anyone help me around this please?
thanks!
this is the code:
combinedString=[[NSMutableArray alloc] init];
NSString *finalStringLabel=#"";
for (i=0; i<=textLength; i++) {
//character coding
char myChar = [myString characterAtIndex:i];
NSString *myCharS=[NSString stringWithFormat:#"%c", myChar];
int asciiCode=[myCharS characterAtIndex:0];
NSString *asciiS=[NSString stringWithFormat:#"%i", asciiCode];
[combinedString addObject:asciiS];
}
finalStringLabel=[NSString stringWithFormat:#"", [combinedString componentsJoinedByString:#"."]];
myLabel.text=finalStringLabel;
[combinedString release];
}
You can use this
NSArray *yourArray;
NSString *createdString = [yourArray componentsJoinedByString:#" "];
myLabel.text = createdString;
As your array is combinedString,
combinedString=[[NSMutableArray alloc] init];
looks like you are providing values after this line or this is not a property (this is a local as you are releasing it later), and your code in not complete.
Anyways,
You don't need to create an empty string and then assign new object to it, need to do as :
myLabel.text=[combinedString componentsJoinedByString:#"."];
[combinedString release];
}

Saving int values to Array when app closes

I have an Iphone app that uses alot of int values that will increment on IBActions, I want to save the int values to an array when the app closes so that these values are stores and used when the app is reopened. I am not sure how to write int values into an array. Functionally, I am getting this to wort with text field but not integers i.e.
int count;
code used:
NSArray *values = [[NSArray alloc] initWithObjects:fieldOne.text,fieldTwo.text,count, nil];
This gives an "Assignment makes integer from pointer without cast" message.
Is there anyway to write already stored int values into and array?
code I used is as follows:
I thinks its ok until the calling the data into the array. I have commented out some failed efforts
-(NSString *) saveFilePath{
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
return [[path objectAtIndex:0] stringByAppendingPathComponent:#"savefile.plist"];
}
-(void) applicationDidEnterBackground: (UIApplication *) application{
//NSNumber *num = [[NSNumber alloc]initWithInt:count];
NSArray *values = [[NSArray alloc] initWithObjects:fieldOne.text,fieldTwo.text,[NSNumber numberWithInt:count],nil];
[values writeToFile:[self saveFilePath] atomically:YES];
[values release];
}
- (void)viewDidLoad {
//NSNumber *num = [[NSNumber alloc]initWithInt:count];
NSString *myPath = [self saveFilePath];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:myPath];
if (fileExists) {
NSArray *values = [[NSArray alloc] initWithContentsOfFile:myPath];
fieldOne.text = [values objectAtIndex:0];
fieldTwo.text = [values objectAtIndex:1];
//[NSNumber count intValue] = [values objectAtIndex:2];
[values release];
}
UIApplication *myApp = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector (applicationDidEnterBackground:)name:UIApplicationDidEnterBackgroundNotification object:myApp];
[super viewDidLoad];
}
Thank you for your help.
You should use NSNumber so something like:
NSNumber *num = [NSNumber numberWithInt:int];
which will give you an object containing your int. To read back from it, use [num intValue]
Create a NSNumber object with your count as its value and put the object into your array. NSArrays need to be arrays of objects.
Container classes work with Objects not fundamental types. You have to wrap fundamental types in NSNumber (numbers) , NSData etc.

Random word From Core-data (NSString)

I have a core-data model with a Entity called Goodie with Attribute called thingsYouWant of type String.
i want to pick a random word from "thingsYouWant" when u push a button, and put that in a string with format.
but i keep getting a NSString may not respond to objectAtIndex error ;-(
Update:
here is my working code:
-( void ) viewDidLoad {
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription
entityForName:#"Goodie" inManagedObjectContext:
self.managedObjectContext ]];
NSError *error = nil;
NSArray *array = [self.managedObjectContext
executeFetchRequest:request error:&error];
if (array == nil)
{
// Deal with error...
}
if(array.count > 0){
int r = random()% [array count];
goodie = [array objectAtIndex:r];
} else { // no one to fetch - generate one
goodie = [NSEntityDescription
insertNewObjectForEntityForName:#"Goodie"
inManagedObjectContext:self.managedObjectContext ];
}
- (void) winText {
NSArray *components = [[goodie thingsYouWant]
componentsSeparatedByString:#" "];
NSInteger randomIndex = (random() % [components count]);
NSString *newWord = [components objectAtIndex:randomIndex];
winLabel.text =[NSString stringWithFormat: #"Congratulations,
the carrot you have earned is -->>> %#", newWord];
}
Thank you :-D
Skov
First, array.count is an improper use of dot syntax. count is not a property of NSArray but a method call.
Second, which line is giving you the error? Are you getting it at the [array objectAtIndex:0] or at [goodie.thingsYouWant objectAtIndex:R]? If it is the latter then you need to see what the property thingsYouWant is defined as. I suspect it is a string property.
Update
If you want to grab a word out of a string then you need to split the string up into an array. Using the method -componentsSeparatedByString:. From there you can then grab one of them at random.
An example of this would be:
NSArray *components = [[goodie thingsYouWant] componentsSeparatedByString:#" "];
NSInteger randomIndex = (random() % [components count]);
NSString *newWord = [components objectAtIndex:randomIndex];
Referring to this statement of yours
Goodie with Attribute called
thingsYouWant of type String
I am with Marcus S. Zarra
Please have a look at Non-Standard Persistent Attributes to store your array in core data.

Why am I getting an invalid NSString from SQLite for my UILabel?

I have a view with a UILabel and a UITableView. I'm using this code to get a string from a database:
-(void)getOneQuestion:(int)flashcardId categoryID:(int)categoryId {
flashCardText=[[NSString alloc] init];
flashCardAnswer=[[NSString alloc] init];
NSString *martialStr=[NSString stringWithFormat:#"%d", flashcardId];
NSString *queryStr=[[NSString alloc] initWithString:#"select flashCardText,flashCardAnswer,flashCardTotalOption from flashcardquestionInfo where flashCardId="];
queryStr=[queryStr stringByAppendingString:martialStr];
NSString *martialStr1=[NSString stringWithFormat:#"%d", categoryId];
NSString *queryStr2=[[NSString alloc] initWithString:#" and categoryId="];
queryStr2=[queryStr2 stringByAppendingString:martialStr1];
queryStr=[queryStr stringByAppendingString:queryStr2];
unsigned int lengthOfString=[queryStr length];
char temp2[lengthOfString +1];
strcpy(temp2, [queryStr cStringUsingEncoding:NSUTF8StringEncoding]);
clsDatabase *clsDatabaseObject = [[clsDatabase alloc] init];
sqlite3_stmt *dataRows = [clsDatabaseObject getDataset:temp2];
while(sqlite3_step(dataRows) == SQLITE_ROW) {
flashCardText =[NSString stringWithUTF8String:(char *)sqlite3_column_text(dataRows,0)];
flashCardAnswer=[NSString stringWithUTF8String:(char *)sqlite3_column_text(dataRows,1)];
flashCardTotalOption=sqlite3_column_int(dataRows,2);
}
sqlite3_reset(dataRows);
sqlite3_finalize(dataRows);
[clsDatabaseObject release];
}
When I click on the table cell, the string value (flashCardAnswer) shows invalid.
Although this code snippet doesn't seem to show where the string value is assigned to the UI element, it would seem that the problem could stem from your use of +[NSString stringWithUTF8String:] inside the while loop. This returns an autoreleased string which you much retain if you want to use it outside the scope of the method. Since those appear to be instance variables that you use in another part of the code to change the UI, you have a few options:
Send a -retain to each of them before exiting the method.
Use +alloc and -initWithUTF8String:.
Use a setter method or property that takes care of the details for you. (Thanks, Chuck!)
As a bonus, I have a few other related suggestions.
You're leaking memory by allocating strings for flashCardText and flashCardAnswer at the start of the method, since you overwrite them in the while loop.
Use -[NSString getCString:maxLength:encoding:] to write the query string into a char* buffer without the strcpy() call, or just use the char* from -cStringUsingEncoding: directly.
There is a lot of potential for simplifying the construction of your query string — definitely investigate NSMutableString. For example...
NSMutableString* query = [[NSMutableString alloc] initWithString:#"select flashCardText,flashCardAnswer,flashCardTotalOption from flashcardquestionInfo"];
[query appendFormat:#" where flashCardId=%d", flashcardId];
[query appendFormat:#" and categoryId=%d", categoryId];
clsDatabase *clsDatabaseObject = [[clsDatabase alloc] init];
sqlite3_stmt *dataRows = [clsDatabaseObject getDataset:[query cStringUsingEncoding:NSUTF8StringEncoding]];