I looked and looked and looked for this and when i finally find something it does not work. I am trying to save and load text color that the user selects. Here is my save button:
-(IBAction)save123456 {
NSData *colorData = [NSKeyedArchiver archivedDataWithRootObject:textview];
[[NSUserDefaults standardUserDefaults] setObject:colorData forKey:#"myColor"];
}
And here is my load:
-(IBAction)load123456 {
NSData *colorData = [[NSUserDefaults standardUserDefaults] objectForKey:#"myColor"];
UIColor *color = [NSKeyedUnarchiver unarchiveObjectWithData:colorData];
}
My text view is textview if that helps. Also i am linking everything via tuchupinside so let me know if i should change anything.
Also if anyone knows how to save text font that the user selects would also be helpful. Thanks so much!!
Well , you could save the RGB of the color. And the font-name of the font.
So when you're saving , store these values for font: font.fontName , font.pointSize
and RGB of the color. Here you can see how to get the RGB of a UIColor object.
These are all NSString and float values so you shouldn't have any problem in saving them.
- (NSString *) pahtForFile:(NSString*) filename
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:filename];
}
- (void) save
{
//get RGB and fontName , fontSize like I explained above
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
[dictionary setObject:fontName forKey:#"fontName"];
[dictionary setObject:[NSNumber numberWithFloat:fontSize] forKey:#"fontSize"];
[dictionary setObject:[NSNumber numberWithFloat:red] forKey:#"red"];
[dictionary setObject:[NSNumber numberWithFloat:green] forKey:#"green"];
[dictionary setObject:[NSNumber numberWithFloat:blue] forKey:#"blue"];
NSString *filepath = [self pathForFile:#"save.plist"];
[dictionary writeToFile:filepath atomically:TRUE];
}
- (void) load
{
float red,green,blue,fontSize;
NSString *fontName;
NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfFile:[self pahtForFile:#"save.plist"]];
red = [[dictionary objectForKey:#"red"] floatValue];
green = [[dictionary objectForKey:#"green"] floatValue];
blue = [[dictionary objectForKey:#"blue"] floatValue];
fontSize = [[dictionary objectForKey:#"fontSize"] floatValue];
fontName = [dictionary objectForKey:#"fontName"];
//now rebuild color and font like this:
UIColor *color = [UIColor colorWithRed:red green:green blue:blue alpha:1];
UIFont *font = [UIFont fontWithName:fontName size:fontSize];
}
Hope this helps.
BTW: If you find the answer useful , mark it as correct.
Cheers,
George
Related
This question already has answers here:
Working with data in iOS Apps (What to choose? NSData, CoreData, sqlite, PList, NSUserDefaults)
(2 answers)
Closed 9 years ago.
I've been struggling with this for ages now and I really need some good help here. :)
I have an app where I'm parsing a quite big JSON into appdelegate's didFinishLaunchingWithOptions.
My Model Objects are:
Tab:
NSString *title
NSMutableArray *categories
Category:
NSString *title
NSMutableArray *items
Item
NSString *title
NSString *description
UIImage *image
I need to save the data locally, cause the parsing takes about 15 seconds every time my app starts. I'm using the SBJSON framework.
Here's my code for parsing:
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"json_template" ofType:#"json"];
NSString *contents = [NSString stringWithContentsOfFile: filePath encoding: NSUTF8StringEncoding error: nil];
SBJsonParser *jsonParser = [[SBJsonParser alloc] init];
NSMutableDictionary *json = [jsonParser objectWithString: contents];
tabs = [[NSMutableArray alloc] init];
jsonParser = nil;
for (NSString *tab in json)
{
Tab *tabObj = [[Tab alloc] init];
tabObj.title = tab;
NSDictionary *categoryDict = [[json valueForKey: tabObj.title] objectAtIndex: 0];
for (NSString *key in categoryDict)
{
Category *catObj = [[Category alloc] init];
catObj.name = key;
NSArray *items = [categoryDict objectForKey:key];
for (NSDictionary *dict in items)
{
Item *item = [[Item alloc] init];
item.title = [dict objectForKey: #"title"];
item.desc = [dict objectForKey: #"description"];
item.url = [dict objectForKey: #"url"];
if([dict objectForKey: #"image"] != [NSNull null])
{
NSURL *imgUrl = [NSURL URLWithString: [dict objectForKey: #"image"]];
NSData *imageData = [NSData dataWithContentsOfURL: imgUrl];
item.image = [UIImage imageWithData: imageData];
}
else
{
UIImage *image = [UIImage imageNamed: #"standard.png"];
item.image = image;
}
[catObj.items addObject: item];
}
[tabObj.categories addObject: catObj];
}
[tabs addObject: tabObj];
}
What is the best way of doing this? Using Core Data or NSFileManager?
If you have som code example too it will make me very happy.
This is the last thing i need to fix before the app is ready for app store and it just kills me! I can't solve this problem.
If you are working on iOS then you save a file to the Documents folder. On Mac OS X it would be in the Application Support folder. Since you are on iOS, read this answer for how to access the Documents folder.
All of the objects that you want to store should implement NSCoding. The above variables already do. Should you want to store the tabs, categories and items directly they would need to implement NSCoding. Then all you need is to serialize them to a file. When opening you app you can look for this file and get your objects back without parsing.
The code should look something like this (untested and error checking is ommited for brevity):
- (void) saveStateToDocumentNamed:(NSString*)docName
{
NSError *error;
NSFileManager *fileMan = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docPath = [paths[0] stringByAppendingPathComponent:docName];
if ([fileMan fileExistsAtPath:docPath])
[fileMan removeItemAtPath:docPath error:&error];
// Create the dictionary with all the stuff you want to store locally
NSDictionary *state = #{ ... };
// There are many ways to write the state to a file. This is the simplest
// but lacks error checking and recovery options.
[NSKeyedArchiver archiveRootObject:state toFile:docPath];
}
- (NSDictionary*) stateFromDocumentNamed:(NSString*)docName
{
NSError *error;
NSFileManager *fileMan = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docPath = [paths[0] stringByAppendingPathComponent:docName];
if ([fileMan fileExistsAtPath:docPath])
return [NSKeyedUnarchiver unarchiveObjectWithFile:docPath];
return nil;
}
I have a UITableView populated by a feed from searchtwitter.com. I also have a details table with an image and UILabel. I have all this working, but I want to add a UIButton on the detail page that will save the UIImage and the label into a property list. I'm very new to this; here is what I have so far (not working).
- (IBAction)SaveFriend:(id)sender
{
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [path objectAtIndex:0];
NSString *plistPath = [documentDirectory stringByAppendingPathComponent:#"TwitterFriends.plist"];
NSDictionary * tweet = [[NSDictionary alloc]init];
NSString *text = [tweet objectForKey:#"from_user"];
NSString *user = [tweet objectForKey:#"from_user_name"];
personName.text = text;
personInfo.text = user;
// create dictionary with values in UITextFields
NSDictionary *plistDict = [NSDictionary dictionaryWithObjects: [NSArray arrayWithObjects: personName, personInfo, nil] forKeys:[NSArray arrayWithObjects: #"Name", #"info", nil]];
NSString *error = nil;
// create NSData from dictionary
NSData *plistData = [NSPropertyListSerialization dataFromPropertyList:plistDict format:NSPropertyListXMLFormat_v1_0 errorDescription:&error];
// check is plistData exists
if(plistData)
{
// write plistData to our Data.plist file
[tweet writeToFile:plistPath atomically:YES];
}
else
{
NSLog(#"Error in saveData: %#", error);
[error release];
}
}
Instead of using a .plist, try using an NSArray or NSMutableArray and then the writeToFile method. For example:
NSMutableArray *temp = [NSMutableArray new];
[temp addObject:image];
[temp addObject:label];
[temp writeToFile:[self saveFilePath:#"filename"] atomically:YES];
//Returns the saved information path
- (NSString*) saveFilePath: (NSString *) add
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *path = [paths objectAtIndex:0];
NSString *filename = [path stringByAppendingPathComponent:add];
return filename;
}
I want to check if user is using the latest version of the app. If so, i should color the background of some cells.
This is the code i'm using:
appDelegate.m
NSString *lastVersion = [[NSUserDefaults standardUserDefaults] objectForKey:#"lastVer"];
method where i want to check:
NSString *lastVersion = (NSString *) [[NSUserDefaults standardUserDefaults] objectForKey:#"lastVer"];
NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"];
lastVersion = #"1.3.4";
if(![lastVersion isEqualToString:version]){
cell.backgroundColor = [UIColor yellowColor]; ;
cell.imageView.image = [UIImage imageNamed:#"image.png"];
}
else {
cell.imageView.image = nil;
cell.backgroundColor = [UIColor whiteColor];
}
}
Am i doing it right? Is my code checking for the latest version or? How can i simulate this behavior in the simulator \ on device?
What i want to do is check if the user is using the latest version of the app, in order to call in another NSUserDefaults key to show the cells of my tableView with a different background color.
EDIT
Code i'm using to change the cells background if the user is using the latest version of my app and if the user has used the app less than three times:
NSString *cellValue = cell.textLabel.text;
NSNumber *runNumber = (NSNumber *)[[NSUserDefaults standardUserDefaults] objectForKey:#"runNum"];
NSString *lastVersion = [[NSUserDefaults standardUserDefaults] objectForKey:#"lastVer"];
NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"];
if (!runNumber) {
runNumber = [NSNumber numberWithInt:0];
[[NSUserDefaults standardUserDefaults] setObject:runNumber forKey:#"runNum"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
if([lastVersion isEqualToString:version]){ //check if the user is using the latest version
if ([runNumber intValue] < 4) { //check if user has used the app less than 3 times
if ([cellValue isEqual: "someText"] ){
cell.backgroundColor = [UIColor yellowColor]; ;
cell.imageView.image = [UIImage imageNamed:#"image.png"];
}
else {
cell.imageView.image = nil;
cell.backgroundColor = [UIColor whiteColor];
}
}
else {
cell.imageView.image = nil;
cell.backgroundColor = [UIColor whiteColor];
}
}
}
this code will not set anything..
NSString *lastVersion = [[NSUserDefaults standardUserDefaults] objectForKey:#"lastVer"];
lastVersion = #"1.3.4";
you need a setter:
[[NSUserDefaults standardUserDefaults] setObject: #"1.3.4" forKey:#"lastVer"];//in memory
[[NSUserDefaults standardUserDefaults] synchronize];//to disk
and a getter:
NSString *lastVersion = [[NSUserDefaults standardUserDefaults] objectForKey:#"lastVer"];
edit:
remember that lastVersion is a pointer and you just set it to point somewhere else, that doesn't set it in stdUserDefaults and it doesn't synchronize it to disk.
Surely if you want to check if the user is using the latest version of the app you would need to check with an external resource.
e.g.
Simple HTTP request to your own server, which returns your latest app version.
Then compare this against your current version [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"];
Store the result of this test in NSUserDefaults
How do you save the color of the dot so that when the app is opened and closed the dot is the color it was last set to by the user?
Could someone explain to me how to use NSUserDefaults and in which methods to declare NSUserDefaults.
So far i have this:
NSData *data = [NSArchiver archivedDataWithRootObject:color];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:#"MyColor"];
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:#"MyColor"];
NSColor *color = [NSUnarchiver unarchiveObjectWithData:data];
Link for tutorial I followed:
http://www.mactech.com/articles/mactech/Vol.25/25.04/2504RoadtoCode/index.html
This is what I use:
- (NSColor *)colorForKey:(NSString *)key
{
NSData *data;
NSColor *color;
data = [[NSUserDefaults standardUserDefaults] objectForKey:key];
color= [NSUnarchiver unarchiveObjectWithData:data];
if( ! [color isKindOfClass:[NSColor class]] )
{
color = nil;
}
return color;
}
- (void)setColor:(NSColor *)color forKey:(NSString *)key
{
NSData *data = [NSArchiver archivedDataWithRootObject:color];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:key];
[BFChatWindow refresh];
}
I've got a little problem with an Application i am designing at the min but i'm a complete beginner, first of all a little information on what i am trying to accomplish.
I have a plist which populates an NSMutableArray which contains many values each one has a string and a BOOL inside, i can make the program save a copy of the file upon opening the app and load the data into the tableview along with an accessoryview of a checkmark.
now the checkmark works ok and you can select different items and the checkmark only appears on those items none of the others and if you inspect the log the details for each of the items check BOOL is changed but when i come to save a second time the checkmark state is not persisted for when i open the application a second time it just saves it as a 0 everytime.
here is some of my code, any help would be appreciated.
Thanks
Brad
- (void)viewDidLoad {
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"CustomChecklist.plist"];
success = [fileManager fileExistsAtPath:filePath];
NSLog(#"STATUS OF SUCCESS %d",success);
if (!success) {
NSString *path = [[NSBundle mainBundle] pathForResource:#"OriginalChecklist" ofType:#"plist"];
success = [fileManager copyItemAtPath:path toPath:filePath error:NULL];
self.dataArray = [NSMutableArray arrayWithContentsOfFile:filePath];
NSLog(#"IF STATEMENT CREATING THE FILE");
}else {
self.dataArray = [NSMutableArray arrayWithContentsOfFile:filePath];
NSLog(#"IF STATEMENT READING THE FILE");
}
NSLog(#"location information %#", filePath);
[super viewDidLoad];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *kCustomCellID = #"MyCellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCustomCellID];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCustomCellID] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
}
NSMutableDictionary *item = [dataArray objectAtIndex:indexPath.row];
cell.textLabel.text = [item objectForKey:#"text"];
[item setObject:cell forKey:#"cell"];
BOOL checked = [[item objectForKey:#"checked"] boolValue];
UIImage *image = (checked) ? [UIImage imageNamed:#"checked.png"] : [UIImage imageNamed:#"unchecked.png"];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
CGRect frame = CGRectMake(0.0, 0.0, image.size.width, image.size.height);
button.frame = frame; // match the button's size with the image size
[button setBackgroundImage:image forState:UIControlStateNormal];
// set the button's target to this table view controller so we can interpret touch events and map that to a NSIndexSet
[button addTarget:self action:#selector(checkButtonTapped:event:) forControlEvents:UIControlEventTouchUpInside];
button.backgroundColor = [UIColor clearColor];
cell.accessoryView = button;
return cell;
}
- (void)viewWillDisappear:(BOOL)animated
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *savePath = [documentsDirectory stringByAppendingPathComponent:#"CustomChecklist.plist"];
NSLog(#"View Will Disappear SAVE location information %#", savePath);
[dataArray writeToFile:savePath atomically:YES];
}
BOOL is not an object, it is a primitive type. Therefore, it cannot be saved (properly) in an array or dictionary. You need to use the NSNumber class to wrap it:
[NSNumber numberWithBool:checked] //this should be added to the dictionary
I am writing this from my phone, so I can't really see all of your code. But I just wanted to say that what you are trying to achieve can probably be solved by using NSUserdefaults instead of saving a file. Have you looked into that?
Oh, and just like Evan said, bool isn't an object. Only objects can be stored in an array.
Is there a reason you are adding the cell to your dictionary? A UITableViewCell is not a property list compatible object, so it could keep your array from saving properly.