I have an array like this: CGPoint array[1000] (I add location of touches into this array). The problem is that I want to save this array into a text file in the document directory and also retrieve it. Can anyone help with this?
Thanks All
Instead of using a plain C array, I would recommend that you use an NSArray to store your collection of CGPoints. Since NSArray conforms to the NSCoding protocol, you can serialize and deserialize it from a file.
You should read up on Archives and Serializations Programming Guide.
EDIT Here's an example:
// Create an NSMutableArray
NSMutableArray *points = [[NSMutableArray alloc] init];
// Add a point to the array
// Read up on NSValue objects to understand why you simply cannot add a C
// struct like CGPoint to the array
[points addObject:[NSValue valueWithBytes:&point1 objCType:#encode(CGPoint)]];
// archive the array -- this will store the array in a file
BOOL result = [NSKeyedArchiver archiveRootObject:points toFile:filePath];
NSLog(#"Archival result: %d", result);
// unarchive the array -- this will retrieve your array from the file
NSMutableArray *points2 = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
Related
I'm stuck at json object parsing really tried hard. The problem is how to parse the json object. Here's what i get the response in the log.
{"0":{"**title**":"Test Event","url_title":"test_event1","status":"open","entry_date":"Sep 10, 2012,
05:20:38AM","entry_id":"26","site_id":"1","channel_id":"3","field_dt_40":null,"field_dt_58":null,"channel_title":"News &
Events","channel_name":"news_events","start_date":"1348120800","end_date":"1348120800","start_time": "43200","end_time":"46800","where":"FCF","news_event_description":"<p>\n\tLunch with group.<\/p>\n"},
"1":{"**title**":"Test Event 2","url_title":"test_event_2","status":"open","entry_date":"Sep 10, 2012, 05:20:08AM","entry_id":"28","site_id":"1","channel_id":"3","field_dt_40":null,"field_dt_58":null,"channel_title":"News & Events","channel_name":"news_events","start_date":"1348207200","end_date":"1348207200","start_time":"43200","end_time":"46800","where":"FCF - Lunch","news_event_description":"<p>\n\tThis was a great event.<\/p>\n"},
"2":{"**title**":"Test Event 3","url_title":"test_event_3","status":"open","entry_date":"Sep 10, 2012, 05:20:54AM","entry_id":"29","site_id":"1","channel_id":"3","field_dt_40":null,"field_dt_58":null,"channel_title":"News & Events","channel_name":"news_events","start_date":"1346738400","end_date":"1346738400","start_time":"7200","end_time":"11700","where":"FCF - Lunch","news_event_description":"<p>\n\tFall planning season.<\/p>\n"}}
The problem is i want to show all the titles in the tableview. I can get the single Title by using key 0,1,2. But i want all the titles to be shown at once i parse
Please help me out guys, Thanks in advance.
Suppose jsonDict is your json dictionary.... Try this
NSArray * keys=[[NSArray alloc]init];
keys=[jsonDict allKeys];
NSMutableArray *titles=[[NSMutableArray alloc]init];
for(int i=0;i<[keys count];i++){
[titles addObject:[[jsonDict valueForKey:[keys objectAtIndex:i]]valueForKey:#"title"]];
}
NSLog(#"your array of titles : %#",titles); //use this array to fill your cell
Are you trying to parse the JSON yourself? You might find it easier to use something that's already well tested, such as TouchJSON or Apple's own NSJSONSerilization. The result should be a graph of Objective-C objects that you can use however you like.
In any case, what you've got there is the equivalent of a dictionary of dictionaries. If you have that as a NSDictionary called myJSONDictionary, you can say:
NSArray *theObjects = [myJSONDictionary allValues]; // gets all the objects
NSArray *theTitles = [theObjects valueForKey:#"**title**"]; // gets all the titles
You can also iterate through a dictionary using fast enumeration:
NSMutableArray *theTitles = [NSMutableArray array];
for (NSString *key in myJSONDictionary) {
NSDictionary *object = [myJSONDictionary objectForKey:key];
NSString *title = [object objectForKey:#"**title**"];
[theTitles addObject:title]
}
There's no real advantage to doing that instead of using KVC as in the first example if you just need the titles, but it could be the right choice if you have more complex work to do for each object.
I learn objective-C from Stanford iTunes and i wonder how i should copy a NSMutableArray to NSArray without initialization. I mean:
Is this is correct? with "lazy initialization".
-(void)copyAnArray:(NSMutableArray*)listOfElements {
if(privateElementsLists == nil)
privateElementsLists = [[NSArray alloc] initWithArray:listOfElements copyItems:YES];
else
privateElementsLists = listOfElements;
}
is this a bad design?
I want to addobjects to mutable array in one class, and then when i'm finish copy entire NSMutableArray to NSArray.
And another question: Why i have to use copyItems:YES when I use initWithArray? And what's deep copy?
You can copy a mutable array to a new array with initWithArray: or this way:
privateElementsLists = [NSArray arrayWithArray:listOfElements];
then you are creating a new array where each of its elements is the same object that figures in the original array. If you write:
privateElementsLists = [NSArray arrayWithArray:listOfElements copyItems:YES];
then the new array have, for each element, a copy of the element in original array. They are not the same object but a copy. Of course, that objects have to be able to respond to copy.
You can even do this:
privateElementsLists = (NSArray*) listOfElements ;
Then the array is exactly the same as the original one. No new array here. But as you have casted it with NSArray pointer class, you can use it as if it is a NSArray instead of a NSMutableArray. As you know, every NSMutableArray is a NSArray (inherited class).
As Joseph DeCarlo stated, you don't need to copy NSMutableArray to NSArray if the only thing you do is to create the array in one place to use it somewhere else. For example this statement is valid:
NSArray* newArray = [NSMutableArray array];
Or in the code:
-(NSArray*)returnAnArray
{
NSMutableArray* editableArray = [NSMutableArray array];
[editableArray addObject:[[NSObject alloc] init]]; //an exemplary object added to the array
return editableArray;
}
That said, however, in some specific cases casting NSMutableArray to NSArray may not be safe, e.g. if the original array was stored in an instance variable. Adding or removing objects to/from that array may cause a crash if the returned array is enumerated at the same time. For example:
-(void)createArray
{
self->editableArray = [NSMutableArray array]; // instance variable: NSMutableArray* editableArray
}
-(void)addObjectToArray
{
[self->editableArray addObject:[[NSObject alloc] init]];
}
-(NSArray*)getArray
{
return self->editableArray;
}
-(void)enumerateArray
{
for(NSObject obj in [self getArray])
{
// do something with obj
}
}
If addObjectToArray is called at the same time as enumerateArray (e.g. from a background thread) the application will crash because the underlying array is changing while it is being enumerated. It doesn't matter that it was returned as NSArray*. In a case like this you would need to either add #synchronized to synchronize access to the same object by multiple threads, or copy the entire array with arrayWithArray: as suggested. Note, however, that the documentation doesn't say if arrayWithArray: is thread safe so I would add #synchronized around the call to arrayWithArray: anyway.
I have a NSMutableArray (tripHistory) that gets a NSMutableDictionary (currentUpdate) added to it every second with new data.
[currentUpdate setObject:testVariable forKey:#"Test"];
[tripHistory addObject:currentUpdate];
[currentUpdate removeAllObjects];
Yet when I loop through tripHistory calling [[tripHistory objectAtIndex:i] description] everything is null.
My loop is as follows:
for (int i=0; i<[tripHistory count]; i++)
{
NSLog(#"%#", [[tripHistory objectAtIndex:i] description]);
}
To initialize my variables, the following code is called only for the first update.
tripHistory = [[NSMutableArray alloc] init];
currentUpdate = [[NSMutableDictionary alloc] init];
Any ideas?
Adding an object to an NSArray doesn't make a copy of it. All that happens is its reference count is incremented. Therefore currentUpdate and the NSDictionary added to tripHistory are one-and-the-same. If you remove objects from currentUpdate you are also removing objects from the NSDictionary in tripHistory.
After adding currentUpdate to tripHistory all you need to do is release currentUpdate and start again with a new empty NSDictionary for the next update.
Do not remove objects. Dictionary and array are keeping references to the same objects. If you want to add another dict to array then release first dict and create a new one
You are removing all of the contents of the dictionary. Adding the dictionary to your array doesn't make a copy: The array will retain a reference to the dictionary, which you proceed to empty out each time you add something to it.
You should allocate a new dictionary each time through the loop and then add that dictionary o the array. If you are not using garbage collection or ARC you should also release the dictionary after it is added to the array.
i have created NSMutableDictionary with 10 keys.Now i want to access NSMutableDictionary keys in a same order as it was added to NSMutableDictionary (using SetValue:* forKey:* );
How can i achieve that ?
If you absolutely must use a dictionary container, you have to use a key that is sortable by the order in which you add key-value pairs. Thus, when creating your dictionary, you use a key that is an auto-incrementing integer or similar. You can then sort on the (integer) keys and retrieve the values associated with those keys.
If you do all of that, however, you may as well just use an NSMutableArray and add values to the array directly! It will be much faster and require less code. You just retrieve objects in order:
for (id obj in myArray) { /* do stuff with obj... */ }
NSMutableDictionary can't do that. Take a look at e.g. Matt Gallaghers OrderedDictionary.
I wrote a quick method to take a source array (of objects that are all out of order) and a reference array (that has objects in a desired (and totally arbitrary) order), and returns an array where the items of the source array have been reorganized to match the reference array.
- (NSArray *) reorderArray:(NSArray *)sourceArray toArray:(NSArray *)referenceArray
{
NSMutableArray *returnArray = [[NSMutableArray alloc] init];
for (int i = 0; i < [referenceArray count]; i++)
{
if ([sourceArray containsObject:[referenceArray objectAtIndex:i]])
{
[returnArray addObject:[arrReference objectAtIndex:i]];
}
}
return [returnArray copy];
}
Note that this is very fragile. It uses NSArray's containsObject: method, which ultimately will call NSObject's isEqual:. Basically, it should work great for arrays of NSStrings, NSNumbers, and maybe NSDates (haven't tried that one yet), but outside of that, YMMV. I imagine if you tried to pass arrays of UITableViewCells or some other really complex object, it would totally sh*t itself, and either crash or return total garbage. Likewise if you were to do something like pass an array of NSDates as the reference array and an array of NSStrings as the source array. Also, if the source array contains items not covered in the reference array, they'll just get discarded. One could address some of these issues by adding a little extra code.
All that said, if you're trying to do something simple, it should work nicely. In your case, you could build up the reference array as you are looping through your setValue:forKey:.
NSMutableArray *referenceArray = [[NSMutableArray alloc] init];
NSMutableDictionary *yourDictionary = [[ NSMutableDictionary alloc] init];
for (//whatever you are looping through here)
{
[yourDictionary setValue://whatever forKey:key];
[referenceArray addObject:key];
}
Then, when you want to loop over your items in the order they came in, you just
for (NSString *key in [self reorderArray:[myDict allKeys] toArray:referenceArray])
Actually you have a reference array in order manner then why you have to add to one more array.So i guess this approach is not good.Please consider my opinion.
Although #GenralMike 's answer works a breeze, it could be optimized by leaving off the unnecessary code as follows:
1) Keep an array to hold reference to the dictionary keys in the order they are added.
NSMutableArray *referenceArray = [[NSMutableArray alloc] init];
NSMutableDictionary *yourDictionary = [[ NSMutableDictionary alloc] init];
for (id object in someArray) {
[yourDictionary setObject:object forKey:someKey];
[referenceArray addObject:someKey]; // add key to reference array
}
2) Now the "referenceArray" holds all of the keys in order, So you can retrieve objects from your dictionary in the same order as they were originally added to the dictionary.
for (NSString *key in referenceArray){
//get object from dictionary in order
id object = [yourDictionary objectForKey:key];
}
I have run into this issue and have put some major time into finding the answer. I am somewhat new to objective c but not to programming.
Here is my question.
I have a plist file with this structure
root {
A (
{songTitle : contents of song},
{songTitle : contents of song}
),
B (
{songTitle : contents of song}
),
C (
{songTitle : contents of song}
),
... kepps going
}
Sorry if the the plist structure is not correct.
Pretty much I have a root dictionary (that is what it comes with) that contains an array of A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,...Z (alphabet)
Each letter of the alphabet array contains 1 or more dictionaries that have a key, value pair of songTitle (this could be any string) as the key and the song lyrics for the value.
My issue here is I need to create an array of all song titles and have been having a rough time trying to find out how to do this. I own 4 books on object c and none of them go into detail about multidimensional arrays and how to access pieces inside them.
I have created an array with all the letters and have created an array that contains the objects from each letter.
Like I stated before I need to find out how to make an array that contains each song title.
If you can help me that would save me a lot of time.
Thanks,
Wes
I am guessing you are suggesting I change my root from a dictionary to an array?
Maybe it might be better to show my code here.
Also I have attached an updated version of my plist file
Sorry seems I cannot add the image here but you can view it
http://www.wesduff.com/images/forum_images/plist_examp.png
So as you can see I have updated the plist file to show the array of letters that each contain multiple dictionaries. Each dictionary has a songTitle and a songLyrics.
How can I write code to get an array of songTitles.
Here is what I have come up with so far
NSString *path = [[NSBundle mainBundle] pathForResource:#"songs" ofType:#"plist"];
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:path];
//This gives me an array of all the letters in alphabetical order
NSArray *array = [[dict allKeys] sortedArrayUsingSelector:#selector(compare:)];
/**
Now I need to find out how to get an array of all songTitles
**/
I am still working on this and looking through what others have written but have not found anything yet.
As the first answer has suggested, should I change the root to an array or keep it as I have it in this plist image I have attached.
Thanks again,
Wes
Ok so I did some more digging and came up with this from the plist file that was included in this picture
http://www.wesduff.com/images/forum_images/plist_examp.png
- (void)viewDidLoad {
//path for plist file
NSString *path = [[NSBundle mainBundle] pathForResource:#"songList" ofType:#"plist"];
//dictionary created from plist file
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:path];
//release the path because it is no longer needed
[path release];
//temp array to hold an array of all alphabetical letters
NSArray *array = [[dict allKeys] sortedArrayUsingSelector:#selector(compare:)];
//assign array to allLetters array
self.allLetters = array;
//Create two mutable arrays for the songArray (could do a little cleaner job of this here)
NSMutableArray *songArray = [[NSMutableArray alloc] init];
NSMutableArray *songTitles = [[NSMutableArray alloc] init];
//Add messy array to songArray then we can work with the songArray (maybe something better to do here)
for(id key in dict)
{
[songArray addObject:[dict objectForKey:key]];
}
//temp array to hold a messy array for all of the songTitles
NSArray *tempArray = [songArray valueForKey:#"songTitle"];
//go through the temparray and clean it up to make one array of all song titles and sort them
for (NSUInteger i = 0; i < [tempArray count]; i++) {
[songTitles addObjectsFromArray:[[tempArray objectAtIndex:i] sortedArrayUsingSelector:#selector(compare:)]];
}
//assign all song titles to our array of songTitles
self.allSongTitles = songTitles;
[dict release];
[allSongTitles release];
[songArray release];
[tempArray release];
[array release];
[super viewDidLoad];
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
I am sure there is probably a better way to do this but this is what I have come up with on my own. Thanks
If you have single array with the contents of all the letters, the rest is fairly simple. Iterate through the objects and call the dictionary method allKeys on each one. Each call to allKeys will return an NSArray containing the keys of that specific dictionary, which you can then place into another array.
EDIT
I made a mistake, didn't go deep enough. This is what I would do:
NSString *path = [[NSBundle mainBundle] pathForResource:#"songs" ofType:#"plist"];
NSDictionary plistDict = [NSDictionary dictionaryWithContentsOfFile:path]; //not using alloc and init means this isn't retained, so it will be autoreleased at the end of the method
NSArray *allLetterContents = [plistDict allValues]; // array of arrays, where each element is the content of a 'letter' in your plist (i.e. each element is an array of dictionaries)
NSMutableArray *allSongTitles = [[[NSMutableArray alloc] init] autorelease];
for(NSArray *oneLetterContents in allLetterContents)
{
for(NSDictionary *song in oneLetterContents)
{
[allSongTitles addObject:[song objectForKey:#"songTitle"]]
}
}
return allSongTitles;
This array isn't guaranteed to be sorted alphabetically, so you'll have to call [sortedArrayUsingSelector:] on it.
Reference:
NSMutableArray Class Reference
NSDictionary Class Reference