Get string from NSArray, saved using NSUserDefaults - objective-c

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];

Related

Encoding issue: An NSString into a key of an NSDictionary

So I'm taking a data file and encoding it into a string:
///////////////////////////////
// Get the string
NSString* dataString = [[NSString alloc] initWithData:data
encoding:encoding];
NSLog(#"dataString = %#",dataString);
The file was a list of French words and they NSLog fine, showing appropriate accents (just one example):
abandonnèrent
Now, in the very next part of the code I take this NSString of the file contents and convert it to a dictionary where the words are the keys and the objects are two additional dictionaries:
///////////////////////////////
// Now parse the file (string)
NSMutableDictionary *mutableWordlist = [[NSMutableDictionary alloc] init];
int i = 0;
for (NSString *line in [dataString componentsSeparatedByString:#"\n"]) {
NSArray *words = [line componentsSeparatedByString:#"\t"];
NSNumber *count = [NSNumber numberWithInt:(i+1)];
NSArray *keyArray;
NSArray *objectArray;
if ([words count] < 2) { // No native word
keyArray = [[NSArray alloc] initWithObjects:#"frequency", nil];
objectArray = [[NSArray alloc] initWithObjects:count, nil];
}
else {
keyArray = [[NSArray alloc] initWithObjects:#"frequency", #"native", nil];
objectArray = [[NSArray alloc] initWithObjects:count, [words[1] lowercaseString], nil];
}
NSDictionary *detailsDict = [[NSDictionary alloc] initWithObjects:objectArray forKeys:keyArray];
[mutableWordlist setObject:detailsDict forKey:[words[0] lowercaseString]];
i++;
}
self.wordlist = mutableWordlist;
NSLog(#"self.wordlist = %#", self.wordlist);
But here the keys have encoding issues and log as so if they have an accent:
"abandonn\U00e8rent
" = {
frequency = 24220;
};
What is happening?
Nothing (wrong) is happening.
When you NSLog an NSString it is being output as Unicode text. However when you NSLog the NSDictionary they keys are being output with unicode escape sequences, \U00e8 is the escape code you can use in a string if you cannot type an è - say because your source file is in ASCII.
So the difference is only in how the string is being printed, the string is not different.
HTH

Sort NSMutableArray based on strings from another NSArray

I have an NSArray of strings that I want to use as my sort order:
NSArray *permissionTypes = [NSArray arrayWithObjects:#"Read", #"Write", #"Admin", nil];
I then have a NSMutableArray that may or may not have all three of those permissions types, but sometimes it will only be 2, sometimes 1, but I still want it sorted based on my permissionsTypes array.
NSMutableArray *order = [NSMutableArray arrayWithArray:[permissions allKeys]];
How can I always sort my order array correctly based on my using the permissionTypes array as a key?
I would go about this by creating a struct or an object to hold the permission types.
Then you can have...
PermissionType
--------------
Name: Read
Order: 1
PermissionType
--------------
Name: Write
Order: 2
and so on.
Then you only need the actual array of these objects and you can sort by the order value.
[array sortUsingComparator:^NSComparisonResult(PermissionType *obj1, PermissionType *obj2) {
return [obj1.order compare:obj2.order];
}];
This will order the array by the order field.
NSMutableArray *sortDescriptors = [NSMutableArray array];
for (NSString *type in permissionTypes) {
NSSortDescriptor *descriptor = [[[NSSortDescriptor alloc] initWithKey:type ascending:YES] autorelease];
[sortDescriptors addObject:descriptor];
}
sortedArray = [myArray sortedArrayUsingDescriptors:sortDescriptors];
Use whichever sorting method on NSMutableArray you prefer, you will either provide a block or a selector to use for comparing two elements. In that block/selector rather than comparing the two strings passed in directly look each up in your permissionTypes array using indexOfObject: and compare the resulting index values returned.
I suggest you another approuch:
- (void)viewDidLoad
{
[super viewDidLoad];
arrayPermissions = [[NSMutableArray alloc] init];
NSDictionary *dicRead = [NSDictionary dictionaryWithObjectsAndKeys:
#"Read", #"Permission", nil];
NSDictionary *dicWrite = [NSDictionary dictionaryWithObjectsAndKeys:
#"Write", #"Permission", nil];
NSDictionary *dicAdmin = [NSDictionary dictionaryWithObjectsAndKeys:
#"Admin", #"Permission", nil];
NSLog(#"my dicRead = %#", dicRead);
NSLog(#"my dicWrite = %#", dicWrite);
NSLog(#"my dicAdmin = %#", dicAdmin);
[arrayPermissions addObject:dicRead];
[arrayPermissions addObject:dicWrite];
[arrayPermissions addObject:dicAdmin];
NSLog(#"arrayPermissions is: %#", arrayPermissions);
// create a temporary Dict again
NSDictionary *temp =[[NSDictionary alloc]
initWithObjectsAndKeys: arrayPermissions, #"Permission", nil];
// declare one dictionary in header class for global use and called "filteredDict"
self.filteredDict = temp;
self.sortedKeys =[[self.filteredDict allKeys]
sortedArrayUsingSelector:#selector(compare:)];
NSLog(#"sortedKeys is: %i", sortedKeys.count);
NSLog(#"sortedKeys is: %#", sortedKeys);
}
hope help

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.

How to put elements from NSMutableArray into C char?

I have a NSMutableArray and I need to sort its elements into separate C char.
How to accomplish that? Or is it better to put the elements into NSStrings?
I've tried this, and it crashes when I try to log the result:
NSMutableArray *array = [[NSMutableArray alloc] init];
... do something to fill the array ...
NSString *string;
string = [array objectAtIndex:0];
NSLog(#"String: %#", string);
*I really prefer putting the elements of the array into C char, because I already have some woking code using char instead of NSStrin*g.
Thanks!
Dont see any specific reason to convert NSString to C chars. To sort an array full of NSStrings try this method -
NSMutableArray *array = [[NSMutableArray alloc] init];
sortedArray = [array sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
NSString *string = [sortedArray objectAtIndex:0];
NSLog(#"String: %#", string);

EXC_BAD_ACESS error

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];