Selecting Multiple Dates in Calendar - ios

I am following This Blog to add a calendar component in my application. Now I want to select more than one dates to show some report for selected dates.
How can I do that ?
Thanks

For this purpose in this tutorial tappedTile method is use for selection of date.so for selecting a number of dates you need to make array and add all the strings.
use like this
NSMutableArray *eventArray//your array for adding dates,make it propeerty and alloc it.
- (void)calendarView:(KLCalendarView *)calendarView tappedTile:(KLTile *)aTile{
int month;
month=[aTile.date monthOfYear];
int day;
day=[aTile.date dayOfMonth];
int year=[aTile.date yearOfCommonEra];
NSString *dateForCompare;
dateForCompare=[NSString stringWithFormat:#"%i/%i/%i",month,day,year];
[eventArray addObject:dateForCompare];
//use this array (having dates in string format).
// use this by using your logical capability
}
see this link,may be it helps you

Related

Get elements from array where date is today

I have an array of objects where a property is date of type NSDate. The array includes future days and past days.
I want to get an array of elements from that array that only includes dates that are in today, not the last 24 hours.
I ordered the elements by descending (new to old):
allDashboards.sortInPlace({ $0.date!.compare($1.date!) == NSComparisonResult.OrderedDescending
I tried to do a for loop, check if date is yesterday and cut the array there, but it doesn't work as it may be no element with a yesterdays date:
for dash in allDashboards {
if (NSCalendar.currentCalendar().isDateInYesterday(dash.date!)) {
print(i)
allDashboards.removeRange(Range.init(start: 0, end: i))
break
}
i += 1
}
Is there a method to see if date is past a day instead of if the date is part of that day?
One-liner:
let todayDashboards = allDashboards.filter { NSCalendar.currentCalendar().isDateInToday($0.date!) }
You can use NSDateComponents to create the dates which represent the start and end of your acceptable range. These can be anything you want.
Once you have those dates, you can create an NSPredicate which matches dates > the start and < the end dates. This will generate a filtered array for you.
You could use isDateInToday to filter the content too.
What you must not do is to iterate the array and mutate it at the same time, which is what your current code does with allDashboards.removeRange inside the for loop.
You can filter all dates which are today with the filter function and isDateInToday of NSCalendar
let filteredDashboards = allDashboards.filter{ NSCalendar.currentCalendar().isDateInToday($0.date!) }

iOS Swift: Sort array into three dimensional array

I have an array of CKRecords that I would like to sort into a three dimensional array. Within the first array is an array of dates, and each date is an array of names, where a name is an Int between 0 and 4. I'm successfully sorting my records into a two dimensional array currently (code below).
Name can be retrieved with record.objectForKey("Name") as Int
func buildIndex(records: [CKRecord]) -> [[CKRecord]] {
var dates = [NSDate]()
var result = [[[CKRecord]]]()
for record in records {
var date = record.objectForKey("startTime") as NSDate
if !contains(dates, date) {
dates.append(date)
}
}
for date in dates {
var recordForDate = [CKRecord]()
for (index, exercise) in enumerate(records) {
let created = exercise.objectForKey("startTime") as NSDate
if date == created {
let record = records[index] as CKRecord
recordForDate.append(record)
}
}
result.append(recordForDate)
}
return result
}
Not sure the best way to approach this problem. Even general guidance would be appreciated.
General Overview:
Step 1 - choose your sort algorithm. I find that the insertion sort algorithm is the easiest for me to understand and is fast too.
Step 2 - decide on your data structure. You could use a 2-dimensional array. The first dimension represents your dates, and the second dimension represents your records. So the array might be defined like this List<List<CKRecord>>. So the first entry would contain a list (List<CKRecord>) of all the records with the earliest date (it may be one or many).
Basic Steps
(with a 2-D array)
So start with the empty data structure
Figure out which Date list it should go into
If the date does not exist yet, you need to sort the date into the correct position and add a new array/list with the new entry as the only contents
If the date already exists, you need to sort the record into the correct position of the already existing list of records
Enjoy

iOS Select specific entries to display in table

I have an array, which contains multiple dictionaries.
Formatted like this:-
Array
- Index
- DOW = Weekday
- Index
- DOW = Weekend
- Index
- DOW = Weekday
I want to populate a table with data from only those dictionaries containing DOW = Weekday.
What is the quickest way of enumerating this?
Note that the data will be changed via filters, and then table reloaded.
You can filter your array using NSPredicate, like this:
NSArray *data = #[
#{#"Dow":#"Weekday", #"One":#"Two"} // Item 0
, #{#"Dow":#"Weekend", #"Three":#"Four"} // Item 1
, #{#"Dow":#"Weekday", #"Five":#"Six"} // Item 2
];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(Dow=='Weekday')"];
NSArray *res = [data filteredArrayUsingPredicate:pred];
The code above will keep NSArrays items 0 and 2, and remove item 1, because it does not contain an entry where #"Dow" is set to #"Weekday".
The data variable above represents the pre-filtered data in your example.
I'd suggest you read Apple UITableViewDataSource protocol guide here and perhaps this tutorial too.
Basically you'll want to -
Override numberOfSectionsInTableView: and return the number of sections in your table (0 if it's not relevant).
Ovveride tableView:numberOfRowsInSection: and here you can "apply" the needed filters on your dictionary and return the correct number of rows you actually want to display.
Next time you update the filters and call reloadTable again the above steps will filter the table correctly according to the new filters.

Nested NSArray filtering

I have the need to obtain the maximum value of a property of a collection of custom objects of the same class. The objects are stored in a NSArray, and the property happens to be another NSArray of numbers.
Let me explain in detail:
NSArray *samples; // of CMData, 4000 elements
CMData is a class that models a sample, for a specific moment in time, of a set of different channels that can have different values.
#interface CMData : NSObject
#property (nonatomic) NSUInteger timeStamp;
#property (nonatomic, strong) NSArray *analogChannelData; // of NSNumber, 128 elements
#end
(I have stripped other properties of the class not relevant to the question)
So for example, sample[1970] could be:
sample.timeStamp = 970800
sample.analogChannelData = <NSArray>
[
[0] = #(153.27)
[1] = #(345.35)
[2] = #(701.02)
...
[127] = #(-234.45)
]
Where each element [i] in the analogChannelData represents the value of that specific channel i for the timeStamp 970800
Now I want to obtain the maximum value for all the 4000 samples for channel 31. I use the following code:
NSUInteger channelIndex = 31;
NSMutableArray *values = [[NSMutableArray alloc] init]; // of NSNumber
// iterate the array of samples and for each one obtain the value for a
// specific channel and store the value in a new array
for (CMData *sample in samples) {
[values addObject:sample.analogChannelData[channelIndex]];
}
// the maximum
NSNumber *maxValue = [values valueForKeyPath:#"#max.self"];
I want to replace this programming structure by a filter through an NSPredcicate or use valueForKeyPath: to obtain the maximum of the data I need.
Anyone knows how to do this without a for loop? Just using NSPredicates and/or valueForKeyPath?
Thank you very much in advance for your help.
Update 1
Finally I benckmarked the for-loop version against the keyPath version (see accepted answer) and it runs much faster so it is better to go with a for loop.
Recalling some lessons from my algorithms classes, I implemented an even faster version that doesn't need an array to store the values. I just iterate over the selected channel and just choose the maximum in each iteration. This is by far the fastest version.
So:
version 1: for loop (see code above)
version 2: version with custom property (see selected answer from Marcus, update 2)
version 3: new code
Code for version 3:
NSUInteger channelIndex = 31;
NSNumber *maxValue = #(-INFINITY);
for (CMTData *sample in samples) {
NSNumber *value = sample.analogChannelData[channelIndex];
if (value) { // I allow the possibility of NSNull values in the NSArray
if ([value compare:maxValue] == NSOrderedDescending)
maxValue = value;
}
}
// the maximum is in maxValue at the end of the loop
Performance:
After 20.000 iterations in iOS simulator:
Version 1: 12.2722 sec.
Version 2: 21.0149 sec.
Version 3: 5.6501 sec.
The decision is clear. I'll use the third version.
Update 2
After some more research, it is clear to me now that KVC does not work for infividual elements in the inner array. See the following links: KVC with NSArrays of NSArrays and Collection Accessor Patterns for To-Many Properties
Anyway because I wanted to compute the maximum of the elements it is better to iterate the array than use some tricks to make KVC work.
You can solve this with using Key Value Coding and the collection operators.
NSNumber *result = [sample valueForKeyPath:#"#max.analogDataChannel"];
Update 1
As Arcanfel mentioned, you can join the arrays together:
NSNumber *result = [samples valueForKeyPath:#"#max.#unionOfArrays.#analogChannelData"];
I would suggest reading the documentation that we both linked to. There are some very powerful features in there.
Update 2
Further to HRD's answer, he has your solution, you need to combine his changes with KVC.
Add a propert to your CMData object for currentChannel. Then you can call
[samples setValue:#(channelIndex) forKey:#"currentChannel"];
Which will set it in every instance in the array. Then call:
[samples valueForKeyPath:#"#max.analogDataForCurrentChannel"];
Then you are done.
I have not tested out the code yet, but I think this is exactly what you are looking for:
[samples valueForKeyPath:#"#max.(#unionOfArrays.analogChannelData)"];
I guess you can also use #distinctUnionOfArray to remove duplicate values.
Here is the link to Apple Documentation that covers collection operators.
Hope this is helpful!
Cheers!
A suggestion for further exploration only
Offhand it is not clear you can do this as-is with a single KVC operator. What you might consider is adding two properties to your class: currentChannel, which sets/gets the current channel; and analogChannelDataForCurrentChannel, which is equivalent to analogChannelData[currentChannel]. Then you can:
samples.currentChannel = channelIndex;
... [samples valueForKeyPath:"#max.analogChannelDataForCurrentChannel"];
with any appropriate locking between the two calls if thread-safety is required (so one thread does not set currentChannel, then a second, and then the first do the KVC operator with the second's channel...).
HTH

Ordering objects under sections

Below is a screenshot of a UITableView that I want to order into by month. Currently their ordered by the first letter of the sub-heading in alphabetical order, what code should I use to make the events ordered into months? (By the way I have worked out how to order the sections)
Any help appreciated,
Seb
The best solution depends on what your data model looks like. Probably the simplest and most efficient, assuming your data model does not change very frequently, is just to have a routine that sorts each section's data in the order you want (based on each item's date). Create a list of pointers (or indices, again depending on your data structure's details), then all you have to do is look up the row index in the section's sorted index structure and display that element's data in your cellForRowAtIndexPath.
To optimize, you can keep a boolean "sorted" field in your data structure that is set to false whenever the data mutates in the table, then only sort on demand in the cellForRowAtIndexPath and set "sorted" to true.
EDIT: request for more step-by-step detailed description
OK, here's a bit more detail on how I'd go about it, assuming each of your sections is stored unsorted in a sortable container like NSMutableArray. Again the best solution depends on the details of your app like how frequently the section entries update and how you organize your data, and is there an upper bound on the number of entries in a section, etc. This is slightly different from my original suggestion in that the section's data container is directly sorted, and doesn't use an external ordering index.
Add a NSMutableSet sortedSections member somewhere convenient, close to your data model (inside its class would be best if you define it in a class)
// a section number is sorted if and only if its number is in the set
NSMutableSet *sortedSections;
When entries in sections are changed, added, or deleted, mark that section as unsorted by removing its number from the set
// just added, deleted, or changed a section entry entry
unsigned int sectionNum; // this section changed
...
NSNumber *nsNum = [NSNumber numberWithUnsignedInt:sectionNum];
[obj.sortedSections removeObject:nsNum];
In your cellForRowAtIndexPath (this may not be the most optimal place for this check, but it is a fast check and is the easiest location to get the sorting working), check if the section is sorted.
unsigned int sectionNum = [indexPath section];
NSNumber *nsNum = [NSNumber numberWithUnsignedInt:sectionNum];
if ( [obj.sortedSections containsObject:nsNum] )
// already sorted, nothing to do
else
{
// section needs to be resorted and reloaded
[mySectionData sortUsingFunction:compareSectionEntriesByDate context:nil];
// mark the section as sorted now
[obj.sortedSections addObject:nsNum];
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationNone];
}
Here is an example sorting function, assuming your entry structures are of type NSDictionary and that you store the dates as NSDate objects with the key constant kEntryNSDate (which you would define yourself)
// sort compare function for two section entries based on date
//
static int compareSectionEntriesByDate( id e1, id e2, void *context)
{
NSDictionary *eDict1 = (NSDictionary *) e1;
NSDictionary *eDict2 = (NSDictionary *) e2;
NSDate *date1 = [eDict1 objectForKey:kEntryNSDate];
NSDate *date2 = [eDict2 objectForKey:kEntryNSDate];
int rv = [date1 compare:date2];
return rv;
}
That should be enough detail to get you going, good luck!

Resources