NSUserDefaults does not pick up setting - ios7

I am quite new to coding in Objective C and using the settings bundle but here is what I coded.
// Set the application defaults
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *appDefaults = [NSDictionary dictionaryWithObject:#"YES"
forKey:#"gameSave"];
[defaults registerDefaults:appDefaults];
[defaults synchronize];
// Get user preference
gameSave = [defaults boolForKey:#"saveGame"];
NSLog(#"Save Game = %#", gameSave ? #"YES" : #"NO");
This is my settings bundle:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreferenceSpecifiers</key>
<array>
<dict>
<key>Title</key>
<string>XXXXXXXXXXXXX</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
<key>FooterText</key>
<string>www.xxxxxxxxxxxx.com</string>
</dict>
<dict>
<key>DefaultValue</key>
<true/>
<key>Key</key>
<string>gameSave</string>
<key>Title</key>
<string>Save Game</string>
<key>Type</key>
<string>PSToggleSwitchSpecifier</string>
</dict>
</array>
<key>StringsTable</key>
<string>Root</string>
</dict>
</plist>
When tested the gameSave value is NO or false. Can someone point me to a solution? Thanks.

#"YES" is a NSString, not a NSNumber containing a boolean.
You want #YES instead:
NSDictionary *appDefaults = [NSDictionary dictionaryWithObject:#YES
forKey:#"gameSave"];
Or the same, shorter:
NSDictionary *appDefaults = #{#"gameSave": #YES};
Edit: what if you do... this?
// Set the application defaults -- only if not written yet
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:#"gameSave"] == nil)
{
[defaults setBool:YES forKey:#"gameSave"];
[defaults synchronize];
}
// Get user preference
gameSave = [defaults boolForKey:#"gameSave"];
NSLog(#"Save Game = %#", gameSave ? #"YES" : #"NO");

This should be straight forward:
To save the bool:
// Write the value to NSUserDefault
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:YES forKey:#"gameIsSaved"];
[defaults synchronize];
To retrieve the boolean value
//Read the value from NSUserDefault
bool gameIsSaved = [defaults boolForKey:#"gameIsSaved"];
NSLog(#"gameIsSaved = %#", gameIsSaved ? #"YES" : #"NO");

Related

Get details from plist file with objective-c

Here is my problem.
I can't seem to figure out how to access the "Details" key in the same level as the "Name" key once search for a specific name key. Maybe I'm missing something?
I know you can get "Details" via [dict objectForKey:#"Details"] but I'm not sure how to get the one on the same levels as the one that was searched for.
Code:
- (IBAction)ScoringButtonView:(id)sender {
ScoringViewController *svController = [[ScoringViewController alloc] initWithNibName:#"ScoringView" bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:svController animated:YES];
UIButton *scoringButton = (UIButton*)sender;
NSLog(#"Scoring is %# ", scoringButton.currentTitle);
svController.ScoringName = scoringButton.currentTitle;
NSString *path = [[NSBundle mainBundle] pathForResource:#"Scoring" ofType:#"plist"];
NSArray *plistData = [NSArray arrayWithContentsOfFile:path];
for (NSDictionary *dict in plistData) {
if ([[dict objectForKey:#"Name"] isEqualToString:scoringButton.currentTitle]) {
NSLog(#"Scoring == %# ", scoringButton.currentTitle);
// svController.ScoringInfo =
}
}
plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<dict>
<key>Name</key>
<string>Standard</string>
<key>Details</key>
<string>dagsdfgds</string>
</dict>
<dict>
<key>Name</key>
<string>Advanced</string>
<key>Details</key>
<string>gfdsgdfsgdsfg</string>
</dict>
</array>
</plist>
I'm not sure what the confusion is. You already know how to get the value for the Name key. Getting the value for the Details key is the same:
for (NSDictionary *dict in plistData) {
if ([dict[#"Name"] isEqualToString:scoringButton.currentTitle]) {
NSString *details = dict[#"Details"];
}
}
Note how I used modern Objective-C syntax instead of the old style use of objectForKey:.
//This method should work fine
//Enumeration method is better than for loop
NSString *filePath = [[NSBundle mainBundle] pathForResource:#“LanguageList” ofType:#"json"];
NSString *myJSON = [[NSString alloc] initWithContentsOfFile:filePath encoding:NSJSONReadingAllowFragments error:NULL];
NSError *error = nil;
NSDictionary * dict = [NSJSONSerialization JSONObjectWithData:[myJSON dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error];
[dict[#"result"] enumerateObjectsUsingBlock:^(id _Nonnull objList, NSUInteger idx, BOOL * _Nonnull stop) {
NSLog(#“Values %#”,obj);
*stop = YES;
}
}];

Service launches my application again and hangs the requesting application

I'm trying to make my program provide a service to look up words. It works when I drag some text onto the icon but when I try to use the menu item it opens another instance of the application, freezes the application I sent the request from for about 30 seconds and then doesn't execute the method it was supposed to.
Here is my method:
- (void)serviceQuery:(NSPasteboard *)pboard userData:(NSString *)userData error:(NSString **)error {
// Test for strings on the pasteboard.
NSArray *classes = [NSArray arrayWithObject:[NSString class]];
NSDictionary *options = [NSDictionary dictionary];
if (![pboard canReadObjectForClasses:classes options:options]) {
*error = NSLocalizedString(#"Error: couldn't encrypt text.",
#"pboard couldn't give string.");
return;
}
NSString *baseURL = #"http://labs.valtyrorn.com/bin/leit.php?q=";
NSString *q = [pboard stringForType:NSPasteboardTypeString];
NSString * encoded = [q stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *query = [NSString stringWithFormat:#"%#%#", baseURL, encoded];
[webView setMainFrameURL:query];
NSLog(query);
}
and the service part of the plist looks like this:
<key>NSServices</key>
<array>
<dict>
<key>NSSendTypes</key>
<array>
<string>NSStringPboardType</string>
</array>
<key>NSMessage</key>
<string>serviceQuery</string>
<key>NSMenuItem</key>
<dict>
<key>default</key>
<string>Fáðu beygingarlýsingu</string>
</dict>
<key>NSPortName</key>
<string>BIN</string>
<key>NSRequiredContext</key>
<dict></dict>
</dict>
</array>
Does anyone know how to fix this?

NSArray initWithContentsOfFile returns nil

I'm trying to read a plist file into NSArray using initWithContentsOfFile as described here
My code looks like this
NSBundle *bundle = [NSBundle mainBundle];
NSString *plistPath = [bundle pathForResource:
#"routes" ofType:#"plist" ];
routes = [[NSArray alloc] initWithContentsOfFile:plistPath ];
NSLog:(#"contents of myArray %#", routes);
routes.plist has a perfectly simple structure of array and 2 string values inside
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Root</key>
<array>
<string>1</string>
<string>2</string>
</array>
</dict>
</plist>
Everything seems to be fine. plistPath initializes with correct value, which means file is copied to the bundle and can be readed. But routes = [[NSArray alloc] initWithContentsOfFile:plistPath ]; returns 0x0 value. I think this is equal to nil
What is wrong with my code?
Actually your plist is a dictionary.
Change this:
<dict>
<key>Root</key>
<array>
<string>1</string>
<string>2</string>
</array>
</dict>
to this:
<array>
<string>1</string>
<string>2</string>
</array>
I think you want to do something like this:
NSBundle *bundle = [NSBundle mainBundle];
NSString *plistPath = [bundle pathForResource:
#"routes" ofType:#"plist"];
NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfFile:plistPath];
NSArray *routes = [dictionary objectForKey:#"Root"];

File Tree Structure into NSDictionary

I'm trying to read a full File/Folder Structure (starting from a given Folder) into an NSDictionary (with a NSArrays,etc), like this :
Let's say starting folder is : /Users/some-user/some-path
We go in there and list all folders/subfolders/files
A/
file_a.txt
file_b.txt
subfolder/
file_c.txt
B/
etc...
What I want is to convert this file structure (probably using enumerators and NSFileManager) into an NSDictionary like :
<key>folder</key>
<string>A</string>
<key>values</key>
<array>
<dict>
<key>file</key>
<string>file_a.txt</string>
<key>url</key>
<string>/Users/some-user/some-path/A/file_a.txt</string>
</dict>
<dict>
<key>file</key>
<string>file_b.txt</string>
<key>url</key>
<string>/Users/some-user/some-path/A/file_b.txt</string>
</dict>
<dict>
<key>folder</key>
<string>subfolder</string>
<key>values</key>
<array>
...
</array>
</dict>
</array>
Any ideas?
Well this is the working result :
To check if a path is a Directory/Package/Bundle, etc :
- (BOOL)isDir:(NSString*)path
{
BOOL isDir;
if (([[NSFileManager defaultManager]
fileExistsAtPath:path isDirectory:&isDir] && isDir) ||
([[NSWorkspace sharedWorkspace] isFilePackageAtPath:path]))
return YES;
else
return NO;
}
The actual function (using recursion) :
- (NSArray*)getContents:(NSString*)path {
NSError* err = nil;
NSArray* files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:&err];
NSMutableArray* conts = [[NSMutableArray alloc] initWithObjects: nil];
for (NSString* c in files)
{
NSDictionary* d;
NSString* p = [d stringByAppendingPathComponent:d];
if (![self isDir:p])
{
d = [NSDictionary dictionaryWithObjectsAndKeys:
c,#"name",
p,#"url", nil];
}
else
{
d = [NSDictionary dictionaryWithObjectsAndKeys:
c,#"group",
p,#"entries", nil];
}
[conts addObject:d];
}
return conts;
}

Objective-C write array to .plist

I have pre-filled information except one string, which will be input by the user. I currently am able to read only a single key with this code:
#define defaultValue #"Someone"
#define myKey #"Event"
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *val = [defaults stringForKey:myKey];
if (val == nil) val = defaultValue;
[myTextField setStringValue:val];
I write it with this code:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *val;
// Get the new value from the textfield
val = [myTextField stringValue];
if ([val isEqualToString:defaultValue]) {
[defaults removeObjectForKey:myKey];
} else {
[defaults setObject:val forKey:myKey];
}
What I really need is to write an array to a .plist like this, and have the 5th string able to be a user input string. How can I do this?:
<plist version="1.0">
<dict>
<key>Event/key>
<dict>
<key>Staff Meeting</key>
<string>Friday Feb 3rd, 2012 </string>
<key>Contact</key>
<string>events#whitehouse.gov</string>
<key>URL</key>
<string>http://www.whitehouse.gov</string>
<key>Status</key>
<string>ATTENDING</string>
<key>Name</key>
<string>Mr. President</string> <------- USER TEXT INPUT
<key>Signature</key>
<data>
20001
</data>
</dict>
</dict>
</plist>
Here an example to create the structure you want.
-(void)saveData:(NSString*)someParam
{
NSMutableDictionary *rootObj = [NSMutableDictionary dictionaryWithCapacity:1];
NSDictionary *innerDict;
NSString *staffMeetingValue;
NSString *contactValue;
NSString *nameValue;
staffMeetingValue = #"Friday Feb 3rd, 2012";
contactValue = #"events#whitehouse.gov";
nameValue = someParam;
innerDict = [NSDictionary dictionaryWithObjects:
[NSArray arrayWithObjects: staffMeetingValue, contactValue, nameValue, nil]
forKeys:[NSArray arrayWithObjects:#"Staff Meeting", #"Contact", #"Name"]];
[rootObj setObject:innerDict forKey:#"Event"];
id plist = [NSPropertyListSerialization dataFromPropertyList:(id)rootObj
format:NSPropertyListXMLFormat_v1_0 errorDescription:&error];
}
For other info see Creating Property Lists Programmatically
Hope it helps.
P.S. You have to add keys and objects for other tags. I skipped them for the sake of simplicity.
Edit:
This is a simple example how to do that. staffMeetingValue and contactValue values are hardcoded but you can pass it as parameters as nameValue.
-(void)saveDataWithName:(NSString*)nameValue staffMeting:(NSString*)staffMetingValue contact:(NSString*)contactValue {
// previous stuff here
}