How to load data from a plist for OpenGL Rendering (iPhone)? - 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.

Related

How to use my Class with PList in objective-c?

I have a Class for handling my data in my project, and now I need to store the data.
I'd like to use a Plist but I'm a bit unsure of how to start.
My class is pretty simple - 6 pieces of data, flat (no hierarchy).
I want my app to start with no data, so can I assume that I should create the PList programmatically once the User creates their first piece of data? (That is, don't create a .plist file in 'Supporting Files' prior to distribution?)
Then, when the app starts the next time, read the data and create an NSMUtableArray array of Class instances?
To create a property list, all you need to do is use appropriate types (i.e. those that support the property list format: NSData, NSString, NSDictionary, NSNumber, NSDate, NSArray), store them in a single container, and tell the containing object to write itself to a file. To read the data, you can initialize that same type using a path. For example:
// writing some data to a property list
NSString *somePath = ... // replace ... with the path where you want to store the plist file
NSMutableDictionary myDict = [NSMutableDictionary dictionary];
[myDict setObject:#"Caleb" forKey:#"name"];
[myDict setObject:[NSNumber numberWithInt:240] forKey:#"cholesterolOrIQ"];
[myDict writeToFile:somePath atomically:YES];
// reading the file again
NSDictionary *readDict = [NSDictionary dictionaryWithContentsOfFile:somePath];
The simplest way is to simple save an NSArray or NSDictionary to disk. Caleb's answer goes into detail there so I won't repeat it, other than to say you might have to convert a non-compatible object like NSColor to an property list object like NSData. It's up to you to do this each time you save or load your data.
NSKeyedArchiver and NSKeyedUnarchiver give you a little more control over the process, but work pretty much the same way. You provide (or get back) a plist compatible root object (usually an NSDictionary) that contains your data. I recommend creating a dictionary that includes your data structure as well as an arbitrary number (your app's build number is a good choice) to use as a version indicator. This way if you ever update your data model you can easily determine if you need to do anything to convert it to the new version.
If you're putting your own objects into the data file, look into NSCoding. The protocol gives you two methods using NSKeyedArchiver and NSKeyedUnarchiver to save and restore your data. This is by far the most straightforward approach if your data model consists of anything more than a few simple strings and numbers, since you're dealing with your own native objects. In your case, you would have your data class implement NSCoding and use the NSKeyedArchiver and NSKeyedUnarchiver methods to encode your six instance variables. When it's time to save or load, pack the instance of your class into an NSDictionary (along with a versioning number as I mentioned above) and call NSKeyedArchiver's archiveRootObject:toFile:. Your save an load methods deal only with your own data object, which makes things easy for you. The common pitfall to watch out for here is if your custom data object contains other custom object. This is fine, but you have to make sure every object that's going to be saved has its own NSCoding implementation.
Two things you can do:
Use NSUserDefaults:
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/Reference/Reference.html
The objectForKey method is the one you want to use to store your class. But, as pointed out in the comments, this shouldn't really be used for storing lots of user data; it's best for saving preferences.
For storing more data, you might want to look at Core Data. It's more complex, but should be better suited to your needs. Here's a tutorial on it:
http://mobile.tutsplus.com/tutorials/iphone/iphone-core-data/
Neither of these seems best for your simple application, but I leave this answer up since it gives alternatives for saving data to the iPhone.

problem in nsuserdefaults

hii every one i have stil problem in nsuser defaults i'll tell the scenerio in detail
First i have diclared nsmutable array in appDelegate and set it in NSUserDefaults With For Key#"abc"
In FirstView Controller i first fetch the array from NSUserDefaults and save its values in NSMutable Array
When a Click say abcButton i have create a dictionary and adding values in it like
[abcDictionar setObject:[[abcMutableArray objectAtIndex:indexPath.row] objectForKey:#"abc"] forKey:#"abc"];
When i added all values in NSDictionary Then i add NSDictionary in NSMutable Array
like This
[abcMutableArray addObject:abcDictionary];
Then i save it NSUserDefaults
It Give me Exception in Point 4
When i add nsdictionary in Point One It All work fine but data in array is ambigous and it raise exception when am going to display it in tableview
if any one has some idea then let me know thanks in advance...:)
NSUserDefaults does not store mutable objects, only immutable ones. When you retrieve objects from it you must cast/copy them into mutable objects if you wish to mutate them.
Also be aware that:
The NSUserDefaults class provides convenience methods for accessing common types such as floats, doubles, integers, Booleans, and URLs. A default object must be a property list, that is, an instance of (or for collections a combination of instances of): NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. If you want to store any other type of object, you should typically archive it to create an instance of NSData.
Which is from the NSUserDefaults documentation.

KVC: How do I save UIKit structs in plist?

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.

Is it possible to store an NSMutableArray together with all its contents into a file and restore it later from there?

Some kind of serialization available in iPhone OS? Is that practically possible or should I quickly forget about that?
I am making a tiny app that stores some inputs in an NSMutableArray. When the user leaves, the inputs should stay alive until he/she returns to continue adding or removing stuff to/from that array.
When the app quits, there must be some way to store all the stuff in the array in a file. Or must I iterate over it, rip everything out and write it i.e. comma-separated somewhere, then the next time go in again, read the stuff in, and iterate over the lines in the file to make an array with that data? That would be hard like a brick. How to?
The easy way, since you already have an NSArray object is to write the array to disk using
- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)flag
and read it back in with:
- (id)initWithContentsOfFile:(NSString *)aPath
or
+ (id)arrayWithContentsOfFile:(NSString *)aPath
You can also use NSCoder.
You can probably search sof for the right code.
So long as the objects in the array implement NSCoding (NSString and NSValue do; if you're storing your own objects it's relatively straightforward), you can use:
[NSKeyedArchiver archiveRootObject: array toFile: filePath];
to save and:
array = [NSKeyedUnarchiver unarchiveObjectWithFile: filePath];
to load.
You can similarly load/save to NSData.
The iPhone SDK is designed to store data using SQLite tables.
You can use NSPropertyListSeralization, since NSArray is a type of property list. You can find more information here.

Saving an NSMutableArray to Core Data

I want to add an NSMutableArray of NSStrings to one of my Entities in my core data model. The problem is that this isn't a supported type in Core Data.
I tried making a tranformable attribute, but the problem is that I see no way of turning a NSMutableArray to NSData, and then going from NSData, back to an NSMutableArray. Does anyone have an idea as to how this issue can be solved?
(I know I can archive the array, but I don't want to do that, I want it to be present in my model).
You could have a binary data attribute in your modeled object, archive the array to data, and hand it off to the object.
But I think the better way would be to have a to-many relationship, instead of using an array directly.
****Edit: Here's how to archive the array into NSData so that it can be used in your managed object***
NSData *arrayData = [NSKeyedArchiver archivedDataWithRootObject:[NSArray arrayWithObjects:#"1",#"2", nil]];
Basically, any class you have which conforms to the NSCoding protocol can be archived in this way. NSArray/NSMutableArray already conform to it. They tell all of their objects to archive themselves, so they must conform too. And all of those objects' members must conform, etc. It's like a tree.
Since your array conforms, and it's an array of NSString (which also conforms), then you're golden.