Accessing Dictionaries inside a Dictionary by Index in Obj-C - objective-c

I'm currently trying to learn Objective-C and I've stumbled across a little problem.
I want to build an iPad Application for collecting simple Numbers,which the User enters, by Date and Time.
To do that I thought of this Structure:
Dictionary("main")
Dictionary("27012013") //this holds all data for the 27th of January 2013
Index = 0
3:33pm = 123 //this would mean at 3:33pm there was a value of 123
..other values to follow
Dictionary("28012013") //and so on
So basically there is one big Dictionary called "main" which holds the dictionaries for all days which then hold their index and all recorded values.
I get the Value's by a UIAlertView Input which then calls the
(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
delegate method in which then the current time and date is saved in NSString's like this:
NSDateFormatter *format = [[NSDateFormatter alloc] init];
[format setDateStyle:NSDateFormatterNoStyle];
[format setTimeStyle:NSDateFormatterShortStyle];
NSString *time = [format stringFromDate:[NSDate date]];
NSLog(#"Time: %# and entered Text:%#",time,returnvalue.text);
//Which Date do we have
[format setDateStyle:NSDateFormatterShortStyle];
[format setTimeStyle:NSDateFormatterNoStyle];
NSString *date = [format stringFromDate:NSDate.date];
NSLog(#"Found Date:%#",date);
NSString *identifier =
[[date componentsSeparatedByCharactersInSet:
[NSCharacterSet punctuationCharacterSet]] componentsJoinedByString:#""];
NSLog(#"Identifier:%#",identifier);
where returnvalue.text holds the entered text. I then check if the dictionary called like the NSString identifier already exist and if not add it to main:
if([main objectForKey:identifier] == nil){
//No Dict Available for current Date so create one:
//there should be no more than 30 Entries per Day
NSMutableDictionary *d = [[NSMutableDictionary alloc] initWithCapacity:30];
[d setObject:identifier forKey:#"Name"];
NSNumber* tmpi = [NSNumber numberWithInteger:main.count];
[d setObject:tmpi forKey:#"Index"];
//and store the recieved value in it
[d setObject:returnvalue.text forKey:time];
[main setObject:d forKey:identifier];
}
else{
NSMutableDictionary *d = [main objectForKey:identifier];
[d setObject:returnvalue.text forKey:time];
}
The First question here is: Do I have to use main.count or main.count+1?
Furthermore I want to display they information in tableView in which each day should have his own section. For the method
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
I therefore need to address they dictionaries inside the main dictionary by Index or e.g. filter them by their Index key to return the number of values inside of them.
I do now I could use a giant NSArray for main but this would make the method for determining if the dictionary for the day already exist more complicated and would rather not want to do this.
So could anyone please help me?
Thanks in Advance

First Answer:
it depends on you but "main.count" will return the number of objects in dictionary may be it's zero. So if you want to start from zero then it's good otherwise +1.
Second Answer:
here is function of NSDictionary "allKeys" which return all the keys as "NSArray" then you can get each key by index if you don't know about the "key" just get it using index from array.

Related

How to combine two key values in the dictionary of array in Objective C

I am having the multiple objects of the dictionary in the array. Now, in particular dictionary i have two keys "category" and "createdDate" from the other key.
Situation : -
I Need an array which having objects in a such a way that, the category which having the same date can be clubbed together and form an object . and Those category having different date is the other object it self.
I am having situation in my mind where i have to put various comparison conditions between the keys , the basic approach of doing it . --- Not Required
Need your valuable suggestion for Different Approach, Which is required, also is not complex. Thanks in advance.
here you go, an example
NSDateFormatter * df = [NSDateFormatter new];
for (id object in self.mainArray) {
[df setDateFormat:#"MM/dd/yyyy"];
NSString *dateString = [df stringFromDate:[object objectForKey:#"createdDate"]];
NSMutableArray *sectionArray = self.totalsSectionDictionary[dateString];
if (!sectionArray) {
sectionArray = [NSMutableArray array];
self.totalsSectionDictionary[dateString] = sectionArray;
}
NSString * tempString = [object valueForKey:#"category"]
[sectionArray addObject:#{#"value" : tempString}];
}
this results in a dictionary of objects combined by date as a string value and inside each one of those date keys resides an array of values for that date. From there, you need to tease out those values and sort them like so:
NSArray * tempUnsortedArray = [self.totalsSectionDictionary allKeys];
NSArray *arrKeys = [tempUnsortedArray sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"MM/dd/yyyy"];
NSDate *d1 = [df dateFromString:(NSString*) obj1];
NSDate *d2 = [df dateFromString:(NSString*) obj2];
return [d2 compare: d1];
}];
NSMutableArray * tempArray1 = [NSMutableArray array];
for (NSInteger i = 0; i < arrKeys.count; i++) {
NSMutableArray *sectionArray = self.totalsSectionDictionary[arrKeys[i]];
}
there you go, the last for loop will allow you to iterate through each section array stored in the original dictionary by date so you can put them into a collection or table view
good luck

Scroll to certain point in tableview

I have a tableview that is filled up with dates. My section header is the month name. You can see my tableview over here.
What I want is that it scrolls to the section of the month of that moment. For setting my section headers I use this method.
id <NSFetchedResultsSectionInfo> theSection = [[self.fetchedResultsController sections] objectAtIndex:section];
static NSArray *monthSymbols = nil;
NSArray *dutchMonths = [[NSArray alloc]initWithObjects:#"Januari",#"Februari",#"Maart",#"April",#"Mei",#"Juni",#"Juli",#"Augustus",#"September",#"Oktober",#"November",#"December", nil];
if (!monthSymbols) {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setCalendar:[NSCalendar currentCalendar]];
[formatter setMonthSymbols:dutchMonths];
monthSymbols = [formatter monthSymbols];
}
NSLog(#"%#",monthSymbols);
NSInteger numericSection = [[theSection name] integerValue];
NSInteger year = numericSection / 1000;
NSInteger month = numericSection - (year * 1000);
NSString *titleString = [NSString stringWithFormat:#"%#", [monthSymbols objectAtIndex:month-1]];
label.text = titleString;
I know already that I have to use this method.
[sampleListTableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
But how do I get the indexpath of the correct row?
Any help? If you need more details. Please help.
Kind regards.
Looks like you can get an index by looping through your sections array (from self.fetchedResultsController) and comparing the month obtained from the object in question to the month from the current date. If you have a match, then your indexPath would be:
NSIndexPath *path = [NSIndexath indexPathForRow:0 inSection:foundIndex];
You should also make the dutchMonths array static so it isn't created every time that method is called. Also, if you aren't using ARC, it's leaking (unless the release code is not posted). A general rule of thumb is to make the date formatter static too, or manage one instance of it in some way, because it is an expensive operation. I know with this code it is only created once since you only use it to populate the monthSymbols array, but if you need to use the same formatter in other code, then you'll want to rewrite that.
To do all of this, you should extract the logic in this method and put it in smaller, reusable methods like
- (NSInteger)monthFromSection:(id<NSFetchedResultsSectionInfo>)section;
Then you can write:
NSIndexPath *path = nil;
NSInteger currentMonth = // Calculate month from date returned by [NSDate date]
NSArray *sections = [self.fetchedResultsController sections];
for (int i = 0; i < sections.count; i++)
{
if (currentMonth = [self monthFromSection:[sections objectAtIndex:i]])
{
path = [NSIndexPath indexPathForRow:0 inSection:i];
break;
}
}

NSMutableDictionary losing object

I'm trying to store arrays of objects in an Mutable Dictionary, but it seems like the dictionary is losing some of my arrays (or maybe the arrays are losing the data?).
Anyways, here's where I'm at:
- (NSDictionary *)getTicketsByDay:(NSArray *)tickets {
// take an array of tickets and return a dictionary with dates (given by
// NSDateFormatterShortStyle) as keys and arrays of tickets as the values
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterShortStyle];
// get NSDate object without time (only month, day, year)
unsigned int flags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
NSCalendar *calendar = [NSCalendar currentCalendar];
NSMutableDictionary *datesDict = [[NSMutableDictionary alloc] init];
for (Ticket *ticket in tickets) {
NSDateComponents *ticketDateNoTimeComponents = [calendar components:flags fromDate:[ticket createdAt]];
NSDate *ticketDateNoTime = [calendar dateFromComponents:ticketDateNoTimeComponents];
NSString *dateString = [formatter stringFromDate:ticketDateNoTime];
NSMutableArray *ticketArray = [datesDict objectForKey:dateString];
NSLog(#"%lu", [ticketArray count]);
if (ticketArray == nil) {
NSLog(#"it's here: %#", dateString);
ticketArray = [[NSMutableArray alloc] init];
}
[ticketArray addObject:ticket];
NSLog(#"%lu", [ticketArray count]);
[datesDict setObject:ticketArray forKey:dateString];
}
return datesDict;
}
But then on the console, at random places (although the same places every time), I get something like
41
41
42
0
it's here: 6/29/12
1
even though the key for the previous objects was also "6/29/12". I've also had it print all the keys in the dictionary and there is only 1.
So somewhere I'm losing my data. What's going on?
I should also mention that I'm on 10.7.4 and using ARC.
The code looks fine to me (if you include suggestions from #ConradShultz)
Note that you don't need to create the ticketDateNoTime since you're using a date format, it will always generate the short format string even if the date contains a time...
So your code could be simplified to:
- (NSDictionary *)getTicketsByDay:(NSArray *)tickets {
// take an array of tickets and return a dictionary with dates (given by
// NSDateFormatterShortStyle) as keys and arrays of tickets as the values
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterShortStyle];
NSMutableDictionary *datesDict = [[NSMutableDictionary alloc] init];
for (Ticket *ticket in tickets) {
NSString *dateString = [formatter stringFromDate:[ticket createdAt]];
NSMutableArray *ticketArray = [datesDict objectForKey:dateString];
NSLog(#"%lu", [ticketArray count]);
if (ticketArray == nil) {
NSLog(#"it's here: %#", dateString);
ticketArray = [[NSMutableArray alloc] init];
[datesDict setObject:ticketArray forKey:dateString];
}
[ticketArray addObject:ticket];
NSLog(#"%lu", [ticketArray count]);
}
return datesDict;
}
From the looks of it you'll merely leak memory, and your way of replacing the dictionary entry with itself seems unusual (but I think it should work), but what makes you think you are loosing objects? You are printing the size of your array, which is different for different date strings, so maybe you just got a new date string which made it create a new array for that date?
And about the memory leaking/the unusual code: a more traditional way would be
NSMutableArray *ticketArray = [datesDict objectForKey:dateString];
if (ticketArray == nil) {
ticketArray = [[NSMutableArray alloc] init];
[datesDict setObject:ticketArray forKey:dateString];
[ticketArray release];
}
[ticketArray addObject:ticket];

How do I sort my UITableViewCells based on the dates in a property list?

(Prepare to witness a newbie being very, very confused at what I'd assume is a basic form of logic that my brain is struggling to grasp.)
I have a .plist file at the moment. In the "Key" column there are names of events (it's just dummy content at the moment), and in the "Value" column there are dates in this format: 19-07-2012. Each row is of the "string" type.
In the viewDidLoad method, I use the following code:
NSString *theFile = [[NSBundle mainBundle] pathForResource:#"dates" ofType:#"plist"];
theDates = [[NSDictionary alloc] initWithContentsOfFile:theFile];
theDatesList = [theDates allKeys];
This loads the plist file into the dictionary, then I load the keys into an array, which is the way I've learned to populate a UITableView, specifically with this code in the cellForRowAtIndexPath method:
NSString *eventFromFile = [theDatesList objectAtIndex:indexPath.row];
NSString *dateFromFile = [theDates objectForKey:[theDatesList objectAtIndex:indexPath.row]];
But what I'm confused about now is, how do I order the cells of the UITableView based on what dates are the soonest? So, the cell for the 19th of July would appear before the 21st of August, no matter what order it's in within the plist file.
Within the UITableViewCell I've managed to calculate the number of days between the current date and the date defined within the plist. That's this code:
// Set the date format
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd-MM-yyyy"];
// Get the current, then future date
NSDate *currentDate = [NSDate date];
NSDate *futureDate = [dateFormatter dateFromString:dateFromFile];
// Create the calendar object
NSCalendar *theCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
// Extract the "day" component from the calendar object
NSDateComponents *theDifferenceBetweenDays = [theCalendar components:NSDayCalendarUnit
fromDate:currentDate
toDate:futureDate
options:0];
NSInteger theRemainingDays = [theDifferenceBetweenDays day];
But I really have no idea what I'm doing. Could someone give me a nudge in the right direction? I've looked into NSSortDescriptors and the sortedArrayUsingSelector method, which seem to be relevant, but the act of actual implementation has left me stuck for the past six hours. Or maybe they're not the right track. Like I said, I'm quite confused.
Thanks.
There are several ways to sort an NSArray of NSDates in descending order.
You could use sortedArrayUsingDescriptors::
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"self" ascending:NO];
theDatesList = [theDatesList sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
But I personally prefer sortedArrayUsingComparator::
theDatesList = [theDatesList sortedArrayUsingComparator:^NSComparisonResult(NSDate *date1, NSDate *date2){
return [date2 compare:date1];
}];
There exists a objective C equvialent for monotouch.dialog.
with this, it should be really easy.

Sort objects of array according to date wise in iphone dev?

I've objects of array, in each object i have different type of strings in one string i am getting date from xml parsing, now my task is that to sort whole data according to time wise(like before date then current date then after date). I am having two problems.
How to sort array on this structure like objects of arrays if simple
then it'll more easy for me?
Which function should I use to sort date wise?
One of several options would be using a comparator block. You didn't provide enough informations, so I made some assumptions:
The date string is at the 3rd index of the NSArrays
The date string looks like 31-12-2011
Code
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateFormat:#"dd-MM-yyyy"];
array = [array sortedArrayUsingComparator: ^(id a, id b) {
NSArray *array1 = (NSArray *)a;
NSArray *array2 = (NSArray *)b;
NSDate *date1 = [dateFormatter dateFromString:[array1 objectAtIndex:2]];
NSDate *date2 = [dateFormatter dateFromString:[array2 objectAtIndex:2]];
return [date1 compare:date2]
}
But you should also consider to have an class representing the data.
In that case you would inter ate over the raw dater and create a object for every data set, put it in an NSMutableArray and sort this. similar.