KVC: How do I save UIKit structs in plist? - iphone

I am using KVC to set properties of objects from a plist. I know I can save them as strings <string>{{66, 114}, {64, 64}}</string> and manually convert to structs, but how can I save for example a CGPoint or CGRect in a plist in a way that Cocoa KVC would understand? The Key-Value Coding Programming Guide seems to indicate that I need to save them as NSValues. How?

The Key-Value Coding Programming Guide seems to indicate that I need to save them as NSValues.
No, you need an NSValue to pass a point or rectangle to setValue:forKey:. The KVC docs aren't talking about saving the values anywhere, since that isn't part of KVC. And you can't save an NSValue in a property list, since it isn't one of the property list classes.
So, you need to convert the rectangle to and from one of the property-list data types. I prefer to convert them to and from strings, which you can do with some of the functions in UIKit.
These are actually Core Graphics structures, not UIKit (hence the names CGPoint and CGRect), so you might expect Core Graphics to have functions for this. Indeed it does, but of a different sort: In CGGeometry, Core Graphics provides functions to convert CGPoints and CGRects to and from dictionaries.
Strings or dictionaries: It's your choice. Whichever you choose, they are property lists, so you can store them in your property list output.
On retrieval, convert the dictionary or string to a point or rectangle, and create an NSValue with that to pass to setValue:forKey:. Of course, this works in reverse the other way: When saving, valueForKey: will give you an NSValue, from which you need to extract the point or rectangle to convert to a dictionary or string to save in the plist.

Related

Check for iVar's Names with respect to NSDictionary keys

I am parsing the values of Json object to my data model, and I am trying to figure out if there is any way to compare the name of the iVar's set for are the same with respect to dictionary keys. I am sure there is a good way to do that, but just can't find the method somehow.
Thanks.
It's a little hard to tell what you're asking, but I think you want Key-Value Coding. In particular, setValuesForKeysWithDictionary: will let you pass a dictionary of property or ivar names and set them for you.

NSKeyedArchiver/NSuserDefaults - saving a CGRect

My app involves a user being able to drag specific items such as volume sliders and UIImage views. My goal is to be able to save the locations of the items so that the user can not have to drag the items again after re-launch. Unfortunately, I have seen errors along taking the 'saving CGRect rect = item.frame to NSuserDefaultsorNSKeyedArchiver' route. Any other suggestions?
You could use NSStringFromgCGRect() and CGRectFromString() to store them.
If you're using keyed archiving on iPhone, UIKit specifically supports an addition that looks like this: -encodeCGRect:forKey: and does precisely what you want. See the Apple docs for NSCoder's UIKit additions.
If you're using NSUserDefaults, you don't get the luxury of using an explicit encoder for CGRects, but as some other answers say, you could save them as strings using NSStringFromCGRect() and its reverse.
You would probably encode CGRect using NSData and then store NSData object using NSUserDefaults or NSKeyedArchiver.
I'm not sure what errors exactly are you referring in your question, maybe more explanation needed?
You have to convert the floats in the CGRect to NSNumbers and then put them in a Dictionary.
If you need to store a lot of CGRects, I recommend creating a little lightweight class with the CGRect elements as archivable NSNumber attributes. Create an initializer that takes a CGRect. Then write quick NSCoder protocol methods so the entire object can be archived
That way you can you quickly and easy convert, store and then retrieve the CGRects.

OSX: How to store objects in plist file in an OO way

I feel a little dumbfounded. I know how to store any kind of "plist supporting" data in a preferences file, such as NSArray, NSDictionary, NSString and their CF counterparts. No problem there.
Now I like to store the values of my custom object this way. I had thought that if I implement some kind of serialization/archiving protocol, I could get NSUserDefaults to understand my class just like it understand NSDictionary.
E.g, implementing the NSCoding protocol should give the NSUserDefaults code all that it needs: I give it the key names along with the values as plist compatible types (NSString, mostly in my case). But my encoder doesn't even get invoked. :(
Then I thought that there must be at least some function that generates a NSDictionary from the NSCoding protocol, so that I can then send this dict to store in the prefs. Ideally, there'd by something like the NSKeyedArchiver that I pass any NSCoding compatible object and it gives me a NSDictionary, and vice versa. But that doesn't appeat to exist in Apple's framework.
Do I have to write that really myself? I'd expect this would be a quite common need.
Note: I realize that NSKeyedArchiver generates a binary plist, which I could write as a plist file. But that's not what I want. I want to add the contents of this object to my app's prefs plist file, i.e. I want to store both my object and other prefs data in the plist file. That's what doesn't seem to be possible with the given functions.
I'm currently just adding objects to an NSDictionary then calling NSDictionary's "writeToFile:atomically:" method. I'm mostly adding strings, and an image as NSData, but I believe anything I add to the NSDictionary that implements the NSCoding protocol should get written to the file.
Then later when I call NSDictionary's initWithContentsOfFile everything gets put back in the dictionary as it had been. Would this work for you - letting the dictionary take care of the serialization stuff?

Storing a C struct in CFMutableDictionary

Since there is no counterpart to NSValue in Core Foundation, how are we supposed to store C structs in a CFMutableDictionary?
First, you can put an NSvalue in a CFMutableDictionary as-is, so the answer is "use NSValue." But I assume the rest of your question is "without using any Cocoa objects." In that case, just create a non-retaining CFMutableDictionary, and you can put any pointer you want into it. See "Defining Custom Collection Callbacks" for some example code. I use these a lot.
Remember that these still have to be pointers, so you're going to have to allocate your structs on the heap, not the stack. And that means that memory management is now your problem. Of course you could create a custom set of callbacks that do whatever you want, so if you're using boost or something else with its own ref-counting system, you can still implement that with CFMutableDictionary.
And of course you can replace the struct with a small data object. That's usually a lot easier. But different problems need different solutions.
CFMutableDictionary
CFDictionaryAddValue
A CFType object or a pointer value to add to the dictionary.
you just pass a pointer to your struct.

How to load data from a plist for OpenGL Rendering (iPhone)?

I have an interesting problem.
I have 4 arrays stored in a .plist file, they are called "vertices", "normals", "texCoords" and "polygons" (this file is attached, along with GLViewController.m).
l want to load these arrays into arrays of type Vertex3D, Vector3D, GLfloat and GLubyte respectively, and then render them using OpenGL.
However, I am unsure how load the arrays and was hoping you might be able to help.
Bear in mind that I will want to modify the size of the arrays in the plist, so their size cannot be assumed to be constant (they could have any number of indices).
Links:
Plist: pastie.org/782396
GLViewController.m: pastie.org/782399
Plists are always loaded into arrays or dictionaries of "plist objects": NSData, NSDate, NSNumber, NSString, NSArray, or NSDictionary. So the only way to deal with them is to load the plist into an array or dictionary, then iterate through the resulting objects in order to build new arrays or whatever of the appropriate type.
So basically you'll need to write some sort of code to "translate" from plist to the object types needed by OpenGL.
Check out NSArray arrayWithContentsOfFile: and NSDictionary dictionaryWithContentsOfFile:
Also see the Property List Programming Guide.