Update original NSMutableArray after filtering with NSPredicate - iphone

I have recently started programming for the iOS Platform but now I need some help figuring out how to do 'something':
For my application I fetch some JSON data and put this data as objects into an Array
This Array is written to my own PLIST file (in the docs directory)
Now when the users starts a sync action I:
Fetch the data from the PLIST
Get the timestamp for a certain object in the Array that came from the PLIST
Use timestamp in new JSON request (for the new data)
So far so good.
Now for my (current) problem -> After receiving the new data (JSON req) I wish to update the timestamp of this 'certain' object in the array (and write this to the Plist).
Using an NSPredicate I am able to find the right set of data within the main Array (stampArr).
NSString *documentsDir = [NSHomeDirectory()stringByAppendingPathComponent:#"Documents"];
NSString *plistPath = [documentsDir stringByAppendingPathComponent:#"stamps.plist"];
NSMutableArray *stampArr = [[NSMutableArray alloc] initWithContentsOfFile:plistPath];
NSPredicate *filter = [NSPredicate predicateWithFormat:#"eventid = 1"];
NSMutableArray *filteredStampArr = [stampArr filteredArrayUsingPredicate:filter];
But now, after I update the filteredStampArr, I want to update the main Array with the data from the filtered Array.
In other words, I need to update the object from the Array with the new 'timestamp' (field of object).
I could off course use something like [stampArr addObject: [filteredStampArr copy]] after changing the filterd array but that would just create a duplicate of the information. I wish to overwrite the original object.
Somehow (I think) I need a 'pointer' that tells me the location of the data in the original array so that I can change the data directly in the main array?
(I hope my questions is clear - If not please say so)

Get the item, find it's index in stampArr and replace it with the newItem.
NSArray *filteredStampArr = [stampArr filteredArrayUsingPredicate:filter];
id item = [filteredStampArr objectAtIndex:0]; // id because the type of the item is not known
NSUInteger itemIndex = [stampArr indexOfObject:item];
[stampArr replaceObjectAtIndex:itemIndex withObject:newItem];

When you get filteredArray, you can directly update objects in it (not replace) and thay willbe uopdated in main array.

Read the API carefully!
try:
[stampArr filterUsingPredicate:];

Related

xcode iPhone array and dictionary [noob]

I'm sorry for this (probably very) noob question, but i've been asked about this and can't see what's wrong (i'm java tought..)
This is what I have, data is loaded via JSON:
NSDictionary *myvalues = [myres objectForKey:#"0"];
this is the content if I output via NSLog:
({id = "1a";myval = 5;},
{id = "2b";myval="24.6";})
how do I iterate through myvalues and how do I get the values id and myval? Something like this i'm getting stuck:
for (NSArray* myvals_array in myvalues)
First it looks like the returned value is an Array, the content inside of the parentheses() denotes this. So I would try and set it as such instead of a Dictionary. Then you can enumerate through the array of dictionary's and get each dictionary inside:
for (id object in myvalues) {
NSDictionary *currentObject = (NSDictionary*)object;
NSString *myID = [currentObject valueForKey:#"id"];
NSString *myValue = [currentObject valueForKey:#"myval"];
NSLog(#"ID:%# VALUE:%#",myID,myValue);
}
This will enumerate through the array and create a dictionary for each entry, then get the values for each of the two elements inside. I just NSLog() them here but you can do whatever you want with the values.

display the contents of 3 xml files in a table view

in my iphone app programmatically i have created 3 directories on ipnone memory , and moved one ImageNames.xml(say it has a multiple tags with the same name) file to each of the 3 folders
i know how to parse a ImageNames.xml file and take the contents in the array,,but i need to display the contents of all 3 Array(each array from separate files) in a table view,,how can i do this,,can any one help me,
i tried in the following way
for(int intVar=0;intVar<[arrDownloadedDirNames count];intVar++)
{
[self ImgNamesXMLParser:[arrDownloadedDirNames objectAtIndex:intVar]];//calling ImageNames.xml xml parser(parameter is the folder names in which xml file exist)
NSMutableSet *set = [NSMutableSet setWithArray:arrImageNames];
[set addObjectsFromArray:arrImageNames];
NSArray *array = [set allObjects];
}
But this didnt work,,can any one sujjest me how can i do this? thanx in advance
you should make 3 NSArray's from the 3 diffrent XML files and then merge them in a NSMutableArray using the addObjectsFromArray method.
I imagine that arrImageNames is the result array after parsing the xmlfile
NSMutableArray* theResultArray =[NSMutableArray alloc] init];
for(int intVar=0;intVar<[arrDownloadedDirNames count];intVar++)
{
[self ImgNamesXMLParser:[arrDownloadedDirNames objectAtIndex:intVar]];//calling ImageNames.xml xml parser(parameter is the folder names in which xml file exist)
//... ...
[theResultArray addObjectsFromArray:arrImageNames];
}
Now theResultArray, should contain the objects from the arrImageName. Use addObjectsFromArray and the array will ad the objects from the (parameter array to the ones it already has)
Not sure whether this is what you require, nevertheless, did you try using arrayByAddingObjectsFromArray instance method. A related post can be found here.

Core data only storing last object of JSON feed

I´m using Core Data as local storage in my app. I´ve set it up properly and made subclasses of NSManagedObject for each entity. However, when I´m trying to insert values into my store, it only inserts the last object from my JSON feed.
res = [JSONHandler requestJSONResponse:jsonString];
shows = [res valueForKeyPath:#"Show.Name"];
NSUInteger showIndex = 0;
for(NSString *showName in shows){
showObject = [NSEntityDescription insertNewObjectForEntityForName:#"Show" inManagedObjectContext:managedObjectContext_];
showObject.name = showName;
showObject.iD = [[res valueForKeyPath:#"Show.Id"]objectAtIndex:showIndex];
showObject.desc = [[res valueForKeyPath:#"Show.Description"]objectAtIndex:showIndex];
showObject.activityType = [[res valueForKeyPath:#"Show.ActivityType"]objectAtIndex:showIndex];
showIndex++;
}
This only stores the last object from my JSON feed. Any idea why?
EDIT: It works fine when I do this:
res = [JSONHandler requestJSONResponse:jsonString];
shows = [res valueForKeyPath:#"Show.Name"];
NSUInteger index = 0;
for(NSString *showName in shows){
show = [NSEntityDescription insertNewObjectForEntityForName:#"Show" inManagedObjectContext:managedObjectContext_];
[show setValue:showName forKey:#"name"];
[show setValue:[[res valueForKeyPath:#"Show.Id"]objectAtIndex:index] forKey:#"iD"];
[show setValue:[[res valueForKeyPath:#"Show.Description"]objectAtIndex:index] forKey:#"desc"];
[show setValue:[[res valueForKeyPath:#"Show.ActivityType"]objectAtIndex:index] forKey:#"activityType"];
index++;
}
It´s basically the same thing, isn´t it? But I want to use subclasses of NSManagedObject instead of doing like I did above. Because in the snippet above show is NSManagedObject *show instead of what it should be: Show *show.
How many shows are there? You can find this by doing: NSLog(#"Number of shows: %d.", shows.count);, assuming that shows is an NSArray. It could be that your Core Data code is fine and the JSON parsing itself is at fault.
EDIT: Also, are you correctly saving the changes to the persistent store?
Usually when you see just one of several objects being saved like this, the problem is that a relationship that should be to-many is improperly set as to-one. No matter how many objects you try to add to the relationship, only the last one is set because the relationship can hold only one value.
I think in this circumstance the problem is most likely in the code of the custom subclass instead of the data model itself given that the data model works with generic NSManagedObjects.

Looping through an dictionary; why do I not get the keys alphabetically?

I am writing an iPhone app using S7Graphview and I have saved some dates and results to a .plist as keys and values in a dictionary, both as strings. My plist looks like this:
<dict>
<key>2011-05-11</key>
<string>23</string>
<key>2011-05-12</key>
<string>23</string>
<key>2011-05-13</key>
<string>23</string>
<key>2011-05-14</key>
<string>43</string>
<key>2011-06-14</key>
<string>43</string>
</dict>
Then I use this loop to load those values into the graphview:
NSMutableDictionary* dictionary = [[NSMutableDictionary alloc]init];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath])
dictionary = [NSMutableDictionary dictionaryWithContentsOfFile:filePath];
int i = 1;
if ([dictionary count] > 0) {
for (NSString* key in dictionary){
NSString* verdiString = [dictionary objectForKey:key];
CGFloat verdi = [verdiString intValue];
NSDate *dato = [[NSDate alloc]init];
NSLog(#"key=%# value=%#", key, [dictionary objectForKey:key]);
dato = [self stringTilDato:key];
[items.list_ addObject:[[GraphInfo alloc] initWithID:i name:verdiString value:verdi date:dato]];
i++;
}
}
The "stringTilDato" method converts the date string to a NSDate. The values get loaded into the items.list, but in the wrong order! The NSLog reports:
key=2011-05-14 value=43
key=2011-05-13 value=23
key=2011-05-12 value=23
key=2011-06-14 value=43
key=2011-05-11 value=23
key=2011-05-14 value=43
key=2011-05-13 value=23
key=2011-05-12 value=23
key=2011-06-14 value=43
key=2011-05-11 value=23
(Don't know why it goes through the keys twice, btw, but I dont't believe that's important). I thought the keys would be read alphabetically, or at least in the order of the plist. Why does the plist get loaded into the dictionary in this order, or is it my loading loop that is the problem?
Hope there is someone out there who can help me :)
A dictionary is not an ordered data structure. You can assume no particular order of the keys, and adding or removing a key can change the order completely. If you need an ordered data structure then use an array, or after getting all the keys sort them.
The documentation for NSDictionary says specifically:
The order of the elements in the array
is not defined.
However, if you want the keys sorted in a particular order, there are at least three methods that return a sorted array of keys. Look at the NSDictionary reference page for methods starting with "keysSortedBy..."
Dictionaries do not ensure an ordered key output. If you want the keys displayed in a particular order, you will have to sort them prior to accessing their values and printing the result.

Bulk update & occasional insert (coredata) - Too slow

Update: Currently looking into NSSET's minusSet
links: Comparing Two Arrays
Hi guys,
Could benefit from your wisdom here..
I'm using Coredata in my app, on first launch I download a data file and insert over 500 objects (each with 60 attributes) - fast, no problem.
Each subsequent launch I download an updated version of the file, from which I need to update all existing objects' attributes (except maybe 5 attributes) and create new ones for items which have been added to the downloaded file.
So, first launch I get 500 objects.. say a week later my file now contains 507 items..
I create two arrays, one for existing and one for downloaded.
NSArray *peopleArrayDownloaded = [CoreDataHelper getObjectsFromContext:#"person" :#"person_id" :YES :managedObjectContextPeopleTemp];
NSArray *peopleArrayExisting = [CoreDataHelper getObjectsFromContext:#"person" :#"person_id" :YES :managedObjectContextPeople];
If the count of each array is equal then I just do this:
NSUInteger index = 0;
if ([peopleArrayExisting count] == [peopleArrayDownloaded count]) {
NSLog(#"Number of people downloaded is same as the number of people existing");
for (person *existingPerson in peopleArrayExisting) {
person *tempPerson = [peopleArrayDownloaded objectAtIndex:index];
// NSLog(#"Updating id: %# with id: %#",existingPerson.person_id,tempPerson.person_id);
// I have 60 attributes which I to update on each object, is there a quicker way other than overwriting existing?
index++;
}
} else {
NSLog(#"Number of people downloaded is different to number of players existing");
So now comes the slow part.
I end up using this (which is tooooo slow):
NSLog(#"Need people added to the league");
for (person *tempPerson in peopeArrayDownloaded) {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"person_id = %#",tempPerson.person_id];
// NSLog(#"Searching for existing person, person_id: %#",existingPerson.person_id);
NSArray *filteredArray = [peopleArrayExisting filteredArrayUsingPredicate:predicate];
if ([filteredArray count] == 0) {
NSLog(#"Couldn't find an existing person in the downloaded file. Adding..");
person *newPerson = [NSEntityDescription insertNewObjectForEntityForName:#"person" inManagedObjectContext:managedObjectContextPeople];
Is there a way to generate a new array of index items referring to the additional items in my downloaded file?
Incidentally, on my tableViews I'm using NSFetchedResultsController so updating attributes will call [cell setNeedsDisplay];
.. about 60 times per cell, not a good thing and it can crash the app.
Thanks for reading :)
I'll begin by saying that I'm still new to using the Core Data framework, but my guess is that your problem lies in the for loop you've posted.
If you look at your loop, each time it executes it creates a new NSPredicate object and then filters your existing array looking for matches. On a small data set this technique would work with seemingly small performance losses; however, with your large data set you will end up spending a lot of time creating NSPredicate objects that only differ in the name you've provided. I would suggest that you look at how to create a single predicate and then use variable substitution to perform the search. For information about variable use in predicates check out: http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/CoreData/Articles/cdImporting.html#//apple_ref/doc/uid/TP40003174
As a side note, you may also consider how you've sorted your data and how you are performing the search operation. And another thing I noticed is that you don't release your NSPredicate object, so you're just tossing memory away too.