Indexing and Sorting a UITableView with Values Parsed from an XML by Date - iphone

I am parsing an XML file from a URL, from this XML I parse titles of events, their dates, and locations of the events among other things. These elements are cached in an array called stories which acts as my data source for my table view. My goal is to display and indexed UITableView with the sections based on the date at which my events take place by month (January's events in a section, February's events in another, with month names as the titles for my sections). The events that will take place soonest will be at the top of my view, events further out should be at the bottom of my list, I don't have to worry about events that have already taken place. So far I've been able to display my event names and their dates as subtitles in my UITableView not sorted or indexed, left in the order by which they were parsed. When I log the stories array I view this in the console:
2013-01-04 00:17:22.332 NumberTwo[72213:c07] the stories array is as follows: (
{
additionalDesc = "";
allday = "Yes.";
endtime = "11:55 PM";
isodate = "2013-05-23";
location = "";
starttime = "12:00 AM";
title = "CST Exam Makeups";
},
{
additionalDesc = "";
allday = "No.";
endtime = "12:00 PM";
isodate = "2013-06-01";
location = "";
starttime = "8:00 AM";
title = "SAT & Subject Tests";
},)
There is an example of two elements in the array, I understand I am going to have break down the stories array into smaller ones based on the month that the events occur but I don't know what that method would look like. Here's my attempt at it in the viewDidLoad.
- (void)viewDidLoad {
[super viewDidLoad];
self.sections = [NSMutableDictionary dictionary];
for (UIEvent *event in stories)
{
NSDate *dateRepresentingThisDay = tempDate;
// If we don't yet have an array to hold the events for this day, create one
NSMutableArray *eventsOnThisDay = [self.sections objectForKey:dateRepresentingThisDay];
if (eventsOnThisDay == nil) {
eventsOnThisDay = [NSMutableArray array];
}
// Add the event to the list for this day
[eventsOnThisDay addObject:event];
}
// Create a sorted list of days
NSArray *unsortedDays = [self.sections allKeys];
self.sortedDays = [unsortedDays sortedArrayUsingSelector:#selector(compare:)];
}
I know the line for (UIEvent *event in stories) must be incorrect but I'm sure what should replace it. tempDate is a formatted date I receive from an NSDateFormatter in another method, and event is meant to refer to an element in my array stories. If you could, point me in the right direction to accomplish my goal, it would be much appreciated. Thank You.

For this you have to use the following steps:
1. On the number of section method of table view write the array count.
2. you also have to modify your array by comparing the dates which are available on stack overflow and arrange in array according to your requirement.
3. Set title by giving title.text = [your array object at index[index path of section]]
4. Now you can give rows as you like in it.
This are just steps you need to follow..
Have you got what I mean to say?

Is it possible for you create a class for the above data and have NSDate property to represent your start date/time of the event? If so, you can make use of NSPredicate to sort the array based on your start date property. You can find details on NSPredicate on this link.

Related

combine UITextFields input into one UITtextField

Im new to xcode and objective c. I have asked this question three times and still can't find a good method or answer. I have several uitextfields that accept user input and adds it to the combinedtextField in order of IBAction used.ie user inputs big in one field,bad in the next one and boy in the third and the result is big bad boy in the combinedtextField.
-(IBAction)addtextField1: (id)sender
{
combinedtextField.text = [NSMutableString stringWithFormat:#"%# %#",
combinedtextField.text,textField1.text];
}
-(IBAction)addtextField2: (id)sender
{
combinedtextField.text = [NSMutableString stringWithFormat:#"%# %#",
combinedtextField.text, textField2.text];
}
-(IBAction)addtextField3:(id)sender
{
combinedtextField.text = [NSMutableString stringWithFormat:#"%# %#",
combinedtextField.text,textField3.text];
}
Now this is where it gets interesting.I need to be able to remove the selected text from the combinedtextField.
-(IBAction)removetextField1:(id)sender
{
//////////????????????////////////////
}
-(IBAction)removetextField2: (id)sender
{
//////////????????????////////////////
}
-(IBAction)removetextField3: (id)sender
{
//////////????????????////////////////
}
If I tap the removetextField2 button it would remove the corresponding text(bad) from the combinedtextField and then it would read (big boy)
Ive looked into nsarrays,nsdictionarys and other methods and have got no where.
Need some way of possibly tagging the input and removing it that way. Example code would be great and very much appreciated.
You've left out some important details about your app, so I'm making some guesses about how it should work.
Perhaps what you should do is keep a mutable array of all of the fragments that have been added to the combined string:
#implementation MyViewController {
    NSMutableArray *fragments_;
}
- (void)viewDidLoad {
[super viewDidLoad];
fragments_ = [[NSMutableArray alloc] init];
}
When one of the add buttons is tapped, you append the corresponding field's text to the array and recompute the combined string:
- (IBAction)addTextField1:(id)sender {
[fragments_ addObject:textField1.text];
[self updateCombinedTextField];
}
- (void)updateCombinedTextField {
combinedTextField.text = [fragments componentsJoinedByString:#" "];
}
When one of the remove buttons is tapped, you try to remove the corresponding field's text from the fragments array and recompute the combined string:
- (IBAction)removeTextField1:(id)sender {
[fragments_ removeObject:textField1.text];
[self updateCombinedTextField];
}
That will remove all occurrences of field 1's text from the fragments array. If you just want to remove one instance, you will need to use indexOfObject: (or one of its variants) followed by removeObjectAtIndex:.
You can't do it in a very trivial way (without anything to add, just 1stroke magic function). But, there's the easy way, which i'd possible gone for.
If you don't need to do it a lot of times, and / or the text is quite small (not like a 500 pages book), then:
Create a boolean array named mark, and mark[i] should mark the i'th text field as 'added'. Then, create a function named reloadCombinedTextField, which creates it again, depended of the mark array. (if mark[i] == true, then we add a textfield's text, otherwise not)
Then, just mark or unmark the needed text fields in every function and call the reload function in the end of every call.
Altho, there is another way, but it can be wrong in situations where your text fields have the same text. The thing is, you just search in your combined text field the text from selected text field (for example, with [NSString rangeOfString] method) and remove it.
If you are going to do it often and the text is really big, then it goes much more complicated. But i'm quite sure, that you won't do this on iOS.

Correct way to modify results array from NSFectchRequest without changing Core Data objects

I am retrieving a fetch from my core data database and trying to iterate through the data and make changes to the data, if necessary. When I change the data in the results array, it turns out that my database is changing in the back end as well, without doing a save. I am wondering what would be a good practice to use to change the data without affecting the back end data.
Here is the code I change the data with:
self.singleDayDataPointsForGraph = [[self fuelPurchaseDataForTimePeriodInMonths:self.numberOfMonthsForGraphView] mutableCopy];
for (int i = 0; i < self.singleDayDataPointsForGraph.count; i++) {
FuelPurchase *currentFuelPurchase = [self.singleDayDataPointsForGraph objectAtIndex:i];
if (i < self.singleDayDataPointsForGraph.count + 1 && self.singleDayDataPointsForGraph.count >= 2) {
FuelPurchase *purchaseToCompare = [self.singleDayDataPointsForGraph objectAtIndex:i + 1];
NSDate *firstDate = currentFuelPurchase.dateTimeStamp;
NSDate *secondDate = purchaseToCompare.dateTimeStamp;
NSDateFormatter *dateComparisonFormatter = [[NSDateFormatter alloc] init];
[dateComparisonFormatter setDateFormat:#"yyyy-MM-dd"];
if([[dateComparisonFormatter stringFromDate:firstDate] isEqualToString:[dateComparisonFormatter stringFromDate:secondDate]] ) {
float firstValue = [purchaseToCompare.fillSavings floatValue];
float secondValue = [currentFuelPurchase.fillSavings floatValue];
purchaseToCompare.fillSavings = [NSNumber numberWithFloat:(firstValue + secondValue)];
[self.singleDayDataPointsForGraph removeObjectAtIndex:i];
}
}
The fuelPurchaseDataForTimePeriodInMonths: method is what performs the fetch and returns an NSArray of results. self. singleDayDataPointsForGraph is an NSMutableArray that stores the results array as a mutable copy. This method basically checks two entries in the database to see if they are the on the same day and if they are, then it adds the fuel purchase amounts to each other and deletes one of the records. I don't want this to change my back end data, but it is.
Thanks very much.
It is doing the right thing. If you take a core data object and modify it, it will reflect immediately whether you save it ot not. The saving part ensures, that if you quit the application and come back the data is saved as well.
So for your situation, I would avoid modifying the actual core data object. Rather create a structure which imitates the core data object and modify that structure.
Example, say my coredata object is Person with attributes name and age.
The object a get from a fetch is say
person1.
You have a class PersonSub with same attributes.
Now you can create
PersonSub *personSub = [[PersonSub alloc] init]; //You can create a custom init to initilize from Person core data if you like.
personSub.name = person1.name;
personSub.age = person1.age;
Now you can modify as follows
personSub.age = personSub.age + 1;

Update original NSMutableArray after filtering with NSPredicate

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:];

Match multiple strings in multiple NSArray

I need to select stories from a NSArray of XML by matching a string from an XML element against a list of strings in another NSArray
The XML contains stories, each story has three criteria, say 'Fruit', 'Veg', 'Spice', each containing a single phrase. A sample story might look like:
<story>
<title>I love cooking</title>
<fruit>Oranges</fruit>
<veg>Cauliflower</veg>
<spice>Mixed spice</spice>
<blurb>losts of text and stuff....</blurb>
</story>
I have three dictionaries of key/value pairs in a NSMutableDictionary generated from a pList
<Fruit:dictionary>
'Ripe bananas' : 1
'Green bananas' : 0
<Veg:dictionary>
'Green beans' : 1
'Cauliflower' : 0
<Spice:dictionary>
'Nutmeg' : 1
'Mixed spice' : 0
I don't know what the keys will be, and I need to match the tag in the story against the keys.
i.e. story fruit tag:'Ripe bananas' MATCHES 'Ripe bananas' in list of fruit keys
I can build three arrays of the keys using
NSMutableDictionary *fruitTagsDict = [prefsDictionary objectForKey:#"Fruits"];
NSArray *fruitTags = [fruitTagsDict allKeys];
I loop through the story XML extracting a tag
for (id myArrayElement in storyArray) {
NSString *fruitString = [NSString stringWithString:[myArrayElement fruit]];
//BOOL isTheObjectThere = [issueTags containsObject:fruitString];
NSString *vegString = [NSString stringWithString:[myArrayElement veg]];
NSString *spiceString = [NSString stringWithString:[myArrayElement spice]];
//if ([[fruitTags objectAtIndex:row] isEqualToString:fruitString]) {
//NSLog(#"Yo %#", fruitString);
// ADD TO A NEW ARRAY OF MATCHING STORIES
//}
// Fails because row is undeclared
}
Then I start to glaze out.
The isTheObjectThere line produces nil then crashes at end of loop
I've looked at:
Filter entire NSDictionaries out of NSArray based on multiple keys
Making the Code check to see if the Text in a Text box matches any of the Strings in an NSArray
It seems predicate is the answer but frankly I getting confused.
What I need to do in metacode
repeat with stories
if storyFruitTag is in fruitTagArray
OR storyVegTag is in vegTagArray
OR storySpiceTag is in spiceTagArray
Add to new array of matching stories
Hopefully I've explained enough to get some pointers, I looked into NSMutableSet and Intersect (Xcode: Compare two NSMutableArrays) but the power of too much information got to me
Here's a simple way to determine whether there are matches using key paths:
if ([prefsDict valueForKeyPath:[NSString stringWithFormat:#"Fruit.%#", storyFruitTag]] ||
[prefsDict valueForKeyPath:[NSString stringWithFormat:#"Veg.%#", storyVegTag]] ||
[prefsDict valueForKeyPath:[NSString stringWithFormat:#"Spice.%#", storySpiceTag]]) {
// one of the story's tags matches a key in one of the corresponding dictionaries
}

new line data in UITextView

i am new in iphone prog...
i am using UITextView to view my data from database...
my app is showing high scores from database.... i stored every row of data in a dictionary and then this dictionary in an array...
then i did reverse of that here....
here nextclass is object of that class where the actual method of select command is......
and highscore is my textview
NSArray *scores = [nextclass score];
NSMutableDictionary *DD;
int a = [scores count];
while(a>0)
{
DD=[scores objectAtIndex:a-1];
highscore.text=[NSString stringWithFormat:#"%# -------------------------- %#",[DD objectForKey:#"name"],[DD objectForKey:#"score"]];
a--;
}
the problem is that it replaces the data which was previously added to the textview.....
but i want to show the whole data row by row
waiting for your response......
please help.....
highscore.text=[NSString stringWithFormat:#"%#%# -------------------------- %#",highscore.text, [DD objectForKey:#"name"],[DD objectForKey:#"score"]];
is one option, also you could use the method
stringByAppendingString