PDA

View Full Version : Saving UIColor on Exit




larswik
Oct 15, 2011, 04:33 PM
I am trying to save a UIColor to an NSMutableDictionary with other items when I use the back button my my NavController. Everything saves and loads again when I click on a button to create the ViewController from the plist file except for the UIColor which is 'null'? I added some NSLogs to see what was happening.

If I delete my plist and start fresh here is what happens. This method checks for the plist file and creates it if it is not there, or loads the information.
- (void)readPlist{
NSString *filePath = [self dataFilePath];
if([[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
savedList = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];


NSArray *tempArray = [[NSArray alloc] initWithArray: [savedList objectForKey:@"monthly"]];
checkNumbers = [[NSMutableArray alloc] initWithArray: tempArray copyItems:YES];
[tempArray release];



NSArray *tempArrayTwo = [[NSArray alloc] initWithArray: [savedList objectForKey:@"total"]];
totalPayments = [[NSMutableArray alloc] initWithArray: tempArrayTwo copyItems:YES];
[tempArrayTwo release];


NSArray *tempArrayThree = [[NSArray alloc] initWithArray: [savedList objectForKey:@"item"]];
NSLog(@"TempArrayThree %@", tempArrayThree);
clientList = [[NSMutableArray alloc] initWithArray: tempArrayThree copyItems:YES];
[tempArrayThree release];


CGColorRef tmpColor = [[savedList objectForKey:@"backgroundColor"] CGColor];
NSLog(@" Temp Color Loaded %@",[savedList objectForKey:@"backgroundColor"]);
backDropColor = [[UIColor alloc] initWithCGColor:tmpColor];
NSLog(@"Color Loaded %@", backDropColor);
}
else{
savedList = [[NSMutableDictionary alloc] init];
[savedList writeToFile: filePath atomically:YES]; // if it can't find it, it writes a blank file.
NSLog(@"No Plist on file - created new one");
checkNumbers = [[NSMutableArray alloc] init];
totalPayments = [[NSMutableArray alloc] init];
clientList = [[NSMutableArray alloc] init];
backDropColor = [[UIColor alloc] initWithRed: 0.7 green:0.7 blue:0.7 alpha:1.0];
NSLog(@"BackGround Color load:%@ ", backDropColor);
}
}


When I write to my plist I have an NSLog that checks to see what is going to be saved.

- (void)writePlist{
NSLog(@"BackGround Color to be saved:%@ ", backDropColor);
[savedList setObject:clientList forKey:@"item"];
[savedList setObject:checkNumbers forKey:@"monthly"];
[savedList setObject:totalPayments forKey:@"total"];
[savedList setObject: backDropColor forKey:@"backgroundColor"];
[savedList writeToFile:[self dataFilePath] atomically:YES];
}

The console print out is this for the NSLog
BackGround Color to be saved:UIDeviceRGBColorSpace 0.567326 0.501412 0.595574 1


But when I try to reload it is returning a 'null'
CGColorRef tmpColor = [[savedList objectForKey:@"backgroundColor"] CGColor];
NSLog(@" Temp Color Loaded %@",[savedList objectForKey:@"backgroundColor"]);
backDropColor = [[UIColor alloc] initWithCGColor:tmpColor];
NSLog(@"Color Loaded %@", backDropColor);

2011-10-15 14:28:02.761 MoneyList[2581:207] Temp Color Loaded (null)

What am I over looking?



ArtOfWarfare
Oct 15, 2011, 05:11 PM
Memory management is my weak spot, but I think this is your issue: You never call retain on the color when you get it back. Try this:

CGColorRef tmpColor = [[[savedList objectForKey:@"backgroundColor"] CGColor] retain];

admanimal
Oct 15, 2011, 05:14 PM
UIColor is not a valid type to store in a property list. You'll need to convert it to NSData first.

Memory management is my weak spot, but I think this is your issue: You never call retain on the color when you get it back. Try this:


It doesn't matter if tmpColor is not retained, because its just being used to initialize a UIColor a few lines later. tmpColor doesn't need to exist once the method it is in returns.

larswik
Oct 15, 2011, 05:23 PM
No I got an error Method -retain not found (return type defaults to ID). I did not think I needed to retain it because within the same method it is being passed to backDropColor which I alloc and init with the tmpColor so I am passing the responsibilities to that object to retain it, which I dealloc later.

Or am I not allowed to store a UIColor in a Dict?

admanimal
Oct 15, 2011, 05:48 PM
Or am I not allowed to store a UIColor in a Dict?

Look at my last post again.

P.S. You can't call retain on a CGColorRef because it's a CoreFoundation type and therefore doesn't inherit from NSObject. You -can- call the C functions CGColorRetain and CGColorRelease on it, but as I said that's not the issue.

chown33
Oct 15, 2011, 05:58 PM
UIColor is not a valid type to store in a property list. You'll need to convert it to NSData first.

Or get the red, green, and blue values as CGFloats, convert each CGFloat to an NSNumber, then store those NSNumbers in the plist, such as in a sub-dictionary with keys "red", "green", and "blue".

larswik
Oct 15, 2011, 06:43 PM
admanimal- I must have cross posted, I did not see the original post. I am actually happy with the responses that you and Chown33 said because in the back of my mind I was thinking of both. I have never used NSData so this will be a good chance. If that would to have failed I thought I might be able to break it down into separate int values and store an an NSNumbers like Chown mentioned and store them in the Dict.

Thanks for then help and explanation as to why I could not store UIColor in a property list.

Sydde
Oct 15, 2011, 08:35 PM
UIColor does not have built-in methods for converting to/from NSData, so you will have to use coders, such as NSKeyedArchiver/NSKeyedUnarchiver to handle this if NSData is the way you want to go.

larswik
Oct 16, 2011, 12:14 AM
I am already ahead of you on that one :) The code works perfectly now

- (void)writePlist{
CGColorRef tmpColor = [self.view.backgroundColor CGColor];
backDropColor = [[UIColor alloc] initWithCGColor:tmpColor];
NSData *backGroundColorStorage = [NSKeyedArchiver archivedDataWithRootObject:backDropColor];

[savedList setObject:clientList forKey:@"item"];
[savedList setObject:checkNumbers forKey:@"monthly"];
[savedList setObject:totalPayments forKey:@"total"];
[savedList setObject:backGroundColorStorage forKey:@"backgroundColor"];
[savedList writeToFile:[self dataFilePath] atomically:YES];
}

I don't understand how you guys remember all this stuff. Maybe when you fully understand the paradigm it becomes transparent how everything functions.

admanimal
Oct 16, 2011, 12:33 AM
I don't understand how you guys remember all this stuff. Maybe when you fully understand the paradigm it becomes transparent how everything functions.

We might remember some stuff, but we're also experts at using the documentation.

chown33
Oct 16, 2011, 02:35 PM
We might remember some stuff, but we're also experts at using the documentation.

For example, the initial problem was related to loading from a plist file. So a reasonable first guess at which documentation to review would be the Property List Programming Guide. If one didn't remember the name of the document, one could still search for keywords like property list.

And we don't forget how to break things down into smaller solvable problems. That process works the same no matter what language or framework you're using. So after determining that UIColor isn't allowed in a plist, the way to solve the problem is to break it down. There are a few ways to break it down, as already outlined: NSData, a set of 3 NSNumbers, keyed archiver. It's just a matter of picking one, based on a suitable reason.

larswik
Oct 16, 2011, 03:29 PM
I did not think to look at the plist because it seemed to be a couple of steps away from my problem. I knew the colors changed on the screen, and I could NSLog what was stored in my object which returned 3 values for the RGB, so I knew my UIColor was fine.

The next logical step for 'me' I took was to store it in an NSMutableDict. I knew my UIColor was an object and I could store objects in a Dict, or so I thought. I did not think that it could be the plist at that point.

I still need to read up on NSData since I don't fully understand what it is doing. I am guessing that it is a wrapper of some kind, kind of like when I need to store an int as an object I need to put it into an NSNumber object 'wrapper'.

Thank you!

chown33
Oct 16, 2011, 04:23 PM
I still need to read up on NSData since I don't fully understand what it is doing. I am guessing that it is a wrapper of some kind, kind of like when I need to store an int as an object I need to put it into an NSNumber object 'wrapper'.

Why guess at all? Why draw any preconceived ideas, which may prove to be wrong?

I think it's much better to approach something unknown with an open mind, rather than preconceptions about it. For one thing, it makes me more likely to see what's really there, rather than interpreting what I see through preconceived expectations. Simple ignorance is easier to remedy than misconceptions, because nothing must first be unlearned.

larswik
Oct 16, 2011, 05:36 PM
Ahhh, but the 'unknown' is a tricky area sometimes for me. I try to approach problems in 2 ways, one use the tools I have learned so far to solve the problems, or keep an open mind and learn what I need to do to solve the new problem via doc's, web search or help.

Originally this did not present its self as an unknown problems since I know how to use NSMutableDicts to store and retrieve object in them. I thought there was a problem with the tools I was already using in my understanding of them. What I learned now is to look past what I think is the obvious problem at hand.

Thanks Chown33 for you help.