I have a tableview with a calendar it's appointments in it. Each day is a separate section.
You can see what I mean over here
Now I want that the tableview scrolls to the section of today or if there is no section for today to the closest one.
I know that I should use the following piece of code:
[tableView scrollToRowAtIndexPath:scrollIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
Now I have an NSMutableDictionary that contains my sorted Appointments/day. You can see the function below:
-(NSDictionary *)sortKalendar:(NSMutableArray *)appointments{
NSMutableDictionary *buffer = [[NSMutableDictionary alloc] init];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"dd-MM-yyyy"];
for (int i = 0; i < appointments.count; i++) {
Appointment *object = [appointments objectAtIndex:i];
NSString *date = [formatter stringFromDate:object.app_start];
if(!(date == NULL) ){
NSLog(#"date is %#",date);
if ([buffer objectForKey:date]) {
[(NSMutableArray *)[buffer objectForKey:date] addObject:object];
} else {
NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithObjects:object, nil];
[buffer setObject:mutableArray forKey:date];
}
}
}
NSDictionary *result = [NSDictionary dictionaryWithDictionary:buffer];
return result;
}
My question is now, how can I find the correct NSIndexpath ?
Thanks in advance !
EDIT
At the moment I'm using the following. But something is still not right.
NSArray *keys = [dictAppointments allKeys];
NSLog(#"KEYS ARE %#",keys) ;
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"dd-MM-yyyy"];
NSArray *sortedArray = [keys sortedArrayUsingComparator:^(id obj1, id obj2) {
NSDate *date1 = [formatter dateFromString:obj1];
NSDate *date2 = [formatter dateFromString:obj2];
NSNumber *interval1 = [NSNumber numberWithDouble:[date1 timeIntervalSinceNow]];
NSNumber *interval2 = [NSNumber numberWithDouble:[date2 timeIntervalSinceNow]];
return (NSComparisonResult)[interval1 compare:interval2];
}];
NSLog(#"Sorted Array %#",sortedArray);
NSString *closestDateString = [sortedArray objectAtIndex:0];
NSLog(#"Closest date string is %#",closestDateString);
int section = [keys indexOfObject:closestDateString];
NSIndexPath *scrollIndexPath = [NSIndexPath indexPathForRow:0 inSection:section];
[tableView scrollToRowAtIndexPath:scrollIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
This gives me the following logs:
2014-01-07 13:28:42.420 Adsolut[9579:60b] KEYS ARE (
"03-12-2013",
"20-12-2013",
"17-12-2013",
"05-01-2014",
"21-12-2013",
"31-12-2013",
"04-01-2014",
"06-01-2014",
"16-01-2014",
"29-12-2013",
"03-01-2014",
"11-01-2014",
"18-12-2013",
"31-01-2014"
)
2014-01-07 13:28:42.437 Adsolut[9579:60b] Sorted Array (
"03-12-2013",
"17-12-2013",
"18-12-2013",
"20-12-2013",
"21-12-2013",
"29-12-2013",
"31-12-2013",
"03-01-2014",
"04-01-2014",
"05-01-2014",
"06-01-2014",
"11-01-2014",
"16-01-2014",
"31-01-2014"
)
You can sort the array using time interval between appointment date and current date,
NSArray *keys = [yourDictionary allKeys];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"dd-MM-yyyy"];
NSArray *sortedArray = [keys sortedArrayUsingComparator:^(id obj1, id obj2) {
NSDate *date1 = [formatter dateFromString:obj1];
NSDate *date2 = [formatter dateFromString:obj2];
NSNumber *interval1 = [NSNumber numberWithDouble:abs([date1 timeIntervalSinceNow])];
NSNumber *interval2 = [NSNumber numberWithDouble:abs([date2 timeIntervalSinceNow])];
return (NSComparisonResult)[interval1 compare:interval2];
}];
And the closest date by,
NSString *closestDateString = [sortedArray objectAtIndex:0];
And from that,
int section = [keys indexOfObject:closestDateString];
NSIndexPath *scrollIndexPath = [NSIndexPath indexPathForRow:0 inSection:section];
Get the list of dates (from your dictionary or one you already have). Sort it. Loop over it (indexOfObjectPassingTest:) to find the date >= today (or use a predicate to filter and then take the first item from the result and get the index).
You have a sorted date array, don't you? Let's say it as dateArray.
Get today date object: NSDate * today = [NSDate date];
Search for dateArray to the nearest date, get the index of nearest date.
NSDate * today = [NSDate date] ;
__block NSUInteger section = NSNotFound ;
__block NSTimeInterval timeInterval = NSTimeIntervalSince1970 ;
[dateArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSDate * date = obj ;
NSTimeInterval ti = [today timeIntervalSinceDate:date] ;
if (ti < 0)
ti = -ti ;
if (ti <= timeInterval) {
section = idx ;
timeInterval = ti ;
} else {
*stop = YES ;
}
}] ;
You know the section index now, let's say it as sectionIndex, the first row index in the section is 0.
So the NSIndexPath is [NSIndexPath indexPathForRow:0 inSection:sectionIndex]
Related
I want to sort the following array based on the Date parameter but the problem is from a server I am not getting a timestamp, I am getting the date as a string, can anyone please help.
NSArray *array = #[
#{#"valid":#"Y",#"mof":#"ON",#"dof":#"17-05-2019",#"rtntype":#"CODE1",#"ret_prd":#"042019"},
#{#"valid":#"Y",#"mof":#"ON",#"dof":#"19-04-2019",#"rtntype":#"CODE1",#"ret_prd":#"032019"},
#{#"valid":#"Y",#"mof":#"ON",#"dof":#"19-04-2019",#"rtntype":#"CODE2",#"ret_prd":#"032019"}
];
I have tried applying the solution but it won't work as the Date we have is in NSString and not in NSDate or NSTimeInterval
[array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
if ([obj1 intValue] == [obj2 doubleValue])
return NSOrderedSame;
else if ([obj1 intValue] < [obj2 doubleValue])
return NSOrderedAscending;
else
return NSOrderedDescending;
}];
I am assuming you have a specific reason to keep data as it is instead of parsing into model class keep it handy.
In your scenario you could try the following code to sort the array:
NSArray *array = #[
#{#"valid":#"Y",#"mof":#"ON",#"dof":#"19-04-2019",#"rtntype":#"CODE1",#"ret_prd":#"032019"},
#{#"valid":#"Y",#"mof":#"ON",#"dof":#"17-05-2019",#"rtntype":#"CODE1",#"ret_prd":#"042019"},
#{#"valid":#"Y",#"mof":#"ON",#"dof":#"19-04-2019",#"rtntype":#"CODE2",#"ret_prd":#"032019"}
];
//NSDateFormatter to convert NSString to NSDate
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"dd-MM-yyyy"];
NSArray *sortedArray = [array sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
if ([obj1 isKindOfClass:[NSDictionary class]]
&& [obj2 isKindOfClass:[NSDictionary class]]) {
NSDictionary *dict1 = (NSDictionary *)obj1;
NSDictionary *dict2 = (NSDictionary *)obj2;
if ([dict1[#"dof"] isKindOfClass:[NSString class]]
&& [dict2[#"dof"] isKindOfClass:[NSString class]]) {
NSString *dof1 = (NSString *) dict1[#"dof"];
NSString *dof2 = (NSString *) dict2[#"dof"];
NSDate *date1 = [formatter dateFromString:dof1];
NSDate *date2 = [formatter dateFromString:dof2];
return [date1 compare:date2];//Update the return based on in which order you want the resulting array
}
}
return NSOrderedSame;
}];
NSLog(#"%#", sortedArray);
And the result is:
(
{
dof = "19-04-2019";
mof = ON;
"ret_prd" = 032019;
rtntype = CODE1;
valid = Y;
},
{
dof = "19-04-2019";
mof = ON;
"ret_prd" = 032019;
rtntype = CODE2;
valid = Y;
},
{
dof = "17-05-2019";
mof = ON;
"ret_prd" = 042019;
rtntype = CODE1;
valid = Y;
}
)
How can I find out the next prayer from the array of times, I have total 6 Prayers at different times and i want to compare each one with current time and have to find out which one is most near as a next prayer, Date format also creating problems because it give always in UTC format and I have to use local time zone, I am using the following code:
NSMutableArray *arrayTimeIntervals = [[NSMutableArray alloc]init];
NSMutableArray *intervals = [[NSMutableArray alloc]init];
NSMutableArray *arrayPrayers = [[NSMutableArray alloc]init];
[arrayPrayers addObject:#{#"prayer":#"prayer 1",#"time":#"1:12 am"}];
[arrayPrayers addObject:#{#"prayer":#"prayer 2",#"time":#"5:45 am"}];
[arrayPrayers addObject:#{#"prayer":#"prayer 3",#"time":#"12:03 pm"}];
[arrayPrayers addObject:#{#"prayer":#"prayer 4",#"time":#"3:30 pm"}];
[arrayPrayers addObject:#{#"prayer":#"prayer 4",#"time":#"6:20 pm"}];
[arrayPrayers addObject:#{#"prayer":#"prayer 6",#"time":#"7:50 pm"}];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"hh:mm a"];
NSMutableArray *dates = [NSMutableArray arrayWithCapacity:arrayPrayers.count];
for (NSDictionary *timeDict in arrayPrayers)
{
NSString *timeString = [timeDict objectForKey:#"time"];
NSString *name = [timeDict objectForKey:#"prayer"];
NSDate *date = [dateFormatter dateFromString:timeString];
[dates addObject:#{#"prayer":name,#"time":timeString, #"date":date}];
}
for (int i =0 ; i<arrayPrayers.count; i++) {
NSDictionary *timeDict = arrayPrayers[i];
NSString *timeString = [timeDict objectForKey:#"time"];
//NSString *name = [timeDict objectForKey:#"prayer"];
NSDate *date = [dateFormatter dateFromString:timeString];
NSComparisonResult result = [[NSDate date] compare:date];
if(result==NSOrderedAscending){
NSLog(#"next prayer");
}else if(result==NSOrderedDescending){
NSLog(#"last prayer");
}else{
NSLog(#"current prayer");
}
if ([date earlierDate:[NSDate date]]) {
NSTimeInterval interval = [date timeIntervalSinceNow];
NSDictionary *tempDict = #{#"Prayer":timeDict,
#"Time":timeString,
#"Index":[NSString stringWithFormat:#"%d",i],
#"Interval":[NSString stringWithFormat:#"%f",interval]};
[arrayTimeIntervals addObject:tempDict];
[intervals addObject:[NSString stringWithFormat:#"%f",interval]];
}
}
NSNumber * min = [intervals valueForKeyPath:#"#min.doubleValue"];
NSUInteger index = 0;
for(int i =0 ; i<intervals.count; i++)
{
NSDictionary* dict = arrayTimeIntervals[i];
if([[dict objectForKey:#"Interval"] intValue] == [min intValue]) {
index = i;
NSLog(#"next prayer is!!!:%ld",index);
break;
}
}
NSDictionary *dict = [arrayTimeIntervals objectAtIndex:index];
NSLog(#"next prayer object is:%#",dict);
i've data from Library that return this:
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:distanceNumber,#"distance",idChallengerN,#"idChallenger",dateFrom, #"date", nil];
[_array addObject:dict];
If i print _array this is there result:
{
date = "2015-07-31 14:50:40 +0000";
distance = "-1";
idChallenger = 43;
},
{
date = "2015-07-31 16:18:57 +0000";
distance = "-1";
idChallenger = "-1";
},
{
date = "2015-07-31 16:19:05 +0000";
distance = "-1";
idChallenger = "-1";
},
and it's ok, now I should get each date and group this _array based on weeks...
I've tried:
NSMutableDictionary *tempDic = [NSMutableDictionary dictionary];
for (int i = 0; i<_array.count; i++) {
NSDictionary *dict = [_array objectAtIndex:i];
NSDate *date = [dict objectForKey:#"date"];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *dateComponents = [calendar components:NSWeekOfYearCalendarUnit fromDate:date];
NSLog(#"date week = %ld",(long)[dateComponents weekOfYear]);
NSNumber *weekN = [NSNumber numberWithInteger:[dateComponents weekOfYear]];
if ([tempDic objectForKey:weekN]) {
//contains
}
else{
//not contains
}
weekN return the number of the week in year based on 'date',
now i'm stuck to how group certain data if have the same number of week, like this for example:
weekN = 31 {
{
idChallenger = 43;
idChallenger = 22;
}
}
weekN = 32 {
{
idChallenger = 55;
idChallenger = 21;
idChallenger = 678;
}
}
thanks to popctrl :
NSMutableArray *weekArray = [NSMutableArray array];
for(int i = 0; i < 52; i++){
[weekArray addObject:[NSMutableArray array]];
}
//This replaces your for loop
for (int i = 0; i<_array.count; i++) {
NSDictionary *dict = [_array objectAtIndex:i];
NSDate *date = [dict objectForKey:#"date"];
NSCalendar *calendar = [NSCalendar currentCalendar];
//Notice that I changed NSWeekOfYearCalendarUnit to NSCalendarUnitWeekOfYear, as NSWeekOfYearCalendarUnit has been deprecated
NSDateComponents *dateComponents = [calendar components:NSCalendarUnitWeekOfYear fromDate:date];
NSMutableArray *innerArray = weekArray[[dateComponents weekOfYear] - 1];
[innerArray addObject:dict];
}
this code produce very well structure, but if I want divide weeks in year before?
If you're looking for something that follows the example you've given at the bottom of your post, that would be an array of arrays, where the first array is indexed by date and the inner arrays have no specific order.
If you would like to preserve the initial dictionary data structure, just make the values contained in that array of arrays the dictionary.
EDIT: Here's the code I would use
//To initialize the array
NSMutableArray *weekArray = [NSMutableArray array];
for(int i = 0; i < 52; i++){
[weekArray addObject:[NSMutableArray array]];
}
//This replaces your for loop
for (int i = 0; i<_array.count; i++) {
NSDictionary *dict = [_array objectAtIndex:i];
NSDate *date = [dict objectForKey:#"date"];
NSCalendar *calendar = [NSCalendar currentCalendar];
//Notice that I changed NSWeekOfYearCalendarUnit to NSCalendarUnitWeekOfYear, as NSWeekOfYearCalendarUnit has been deprecated
NSDateComponents *dateComponents = [calendar components:NSCalendarUnitWeekOfYear fromDate:date];
NSMutableArray *innerArray = weekArray[[dateComponents weekOfYear] - 1];
[innerArray addObject:dict];
}
I'm having trouble updating my old code which made synchronous JSOn calls to a new one which makes asynchronous calls using AFNetworking.
In my old code I was grouping cells with a UICollectionReusableView using a date string ("release_date"), all of this was done in the viewDidLoad. Now with AFNetworking I moved everything out of the viewDidLoad, so I'm stuck trying to figure out how to merge my old code with my new one.
This is the new code I have to parse my JSON with AFNetworking:
- (void)viewDidLoad
{
[super viewDidLoad];
self.upcomingReleases = [[NSMutableArray alloc] init];
[self makeReleasesRequests];
[self.collectionView registerClass:[ReleaseCell class] forCellWithReuseIdentifier:#"ReleaseCell"];
}
-(void)makeReleasesRequests //AFNetworking Call
{
NSURL *url = [NSURL URLWithString:#"http://www.soleresource.com/upcoming.json"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"#");
self.upcomingReleases = [responseObject objectForKey:#"upcoming_releases"];
[self.collectionView reloadData];
} failure:nil];
[operation start];
}
Code I had in my viewDidLoad before I started using AFNetworking to make JSON calls and "group" my cells:
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL *upcomingReleaseURL = [NSURL URLWithString:#"http://www.soleresource.com/upcoming.json"];
NSData *jsonData = [NSData dataWithContentsOfURL:upcomingReleaseURL];
NSError *error = nil;
NSDictionary *dataDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
NSArray *upcomingReleasesArray = [dataDictionary objectForKey:#"upcoming_releases"];
//This is the dateFormatter we'll need to parse the release dates
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
NSTimeZone *est = [NSTimeZone timeZoneWithAbbreviation:#"EST"];
[dateFormatter setTimeZone:est];
[dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:#"en_US"]]; //A bit of an overkill to avoid bugs on different locales
//Temp array where we'll store the unsorted bucket dates
NSMutableArray *unsortedReleaseWeek = [[NSMutableArray alloc] init];
NSMutableDictionary *tmpDict = [[NSMutableDictionary alloc] init];
for (NSDictionary *upcomingReleaseDictionary in upcomingReleasesArray) {
//We find the release date from the string
NSDate *releaseDate = [dateFormatter dateFromString:[upcomingReleaseDictionary objectForKey:#"release_date"]];
//We create a new date that ignores everything that is not the actual day (ignoring stuff like the time of the day)
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components =
[gregorian components:(NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit) fromDate:releaseDate];
//This will represent our releases "bucket"
NSDate *bucket = [gregorian dateFromComponents:components];
//We get the existing objects in the bucket and update it with the latest addition
NSMutableArray *releasesInBucket = [tmpDict objectForKey:bucket];
if (!releasesInBucket){
releasesInBucket = [NSMutableArray array];
[unsortedReleaseWeek addObject:bucket];
}
UpcomingRelease *upcomingRelease = [UpcomingRelease upcomingReleaseWithName:[upcomingReleaseDictionary objectForKey:#"release_name"]];
upcomingRelease.release_date = [upcomingReleaseDictionary objectForKey:#"release_date"];
upcomingRelease.release_date = [upcomingReleaseDictionary objectForKey:#"release_date"];
[releasesInBucket addObject:upcomingRelease];
[tmpDict setObject:releasesInBucket forKey:bucket];
}
[unsortedReleaseWeek sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSDate* date1 = obj1;
NSDate* date2 = obj2;
//This will sort the dates in ascending order (earlier dates first)
return [date1 compare:date2];
//Use [date2 compare:date1] if you want an descending order
}];
self.releaseWeekDictionary = [NSDictionary dictionaryWithDictionary:tmpDict];
self.releaseWeek = [NSArray arrayWithArray:unsortedReleaseWeek];
[self.collectionView registerClass:[ReleaseCell class] forCellWithReuseIdentifier:#"ReleaseCell"];
}
CollectionViewCell
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifier = #"Cell";
ReleaseCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
// Part of my new code AFNetworking
NSDictionary *upcomingReleaseDictionary = [self.upcomingReleases objectAtIndex:indexPath.row];
//
// I had this in my old code
UpcomingRelease *upcomingRelease = [self.releaseWeekDictionary objectForKey:self.releaseWeek[indexPath.section]][indexPath.row];
//
cell.release_name.text = upcomingRelease.release_name;
return cell;
}
This is the rest:
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return [self.releaseWeek count];
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [[self.releaseWeekDictionary objectForKey:self.releaseWeek[section]] count];
}
-(UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
ReleaseWeek *releaseWeek = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:#"releaseWeek" forIndexPath:indexPath];
//We tell the formatter to produce a date in the format "Name-of-the-month day"
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"MMMM dd"];
NSTimeZone *est = [NSTimeZone timeZoneWithAbbreviation:#"EST"];
[dateFormatter setTimeZone:est];
[dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:#"en_US"]];
//We read the bucket date and feed it to the date formatter
NSDate *releaseWeekDate = self.releaseWeek[indexPath.section];
releaseWeek.releaseDate.text = [[dateFormatter stringFromDate:releaseWeekDate] uppercaseString];
return releaseWeek;
}
I'm basically trying to figure out how to take the code that grouped my cells be the date string and integrate it with my new code.
Thanks.
Think MVC. Separate your model (the stuff that comes from the network) into a separate class that does the network operations, and grouping things into arrays and dictionaries. Your view controller should simply observe the model. You can use delegation or (my favorite) KVO to know when the model has updated data available. Then you just update your collection view. Your view controller should simply be an interface between the model and the views. If you separate things out this way you will find that it is much more natural, and you aren't fighting against the system.
You are closer than you think.
Simply put everything you used to do in viewDidLoad: (everything between the assignment of jsonData to the registration of your collection view class) into the callback block of your AFNetworking call (where jsonData is now called responseObject).
At the end of the callback block, simply invoke [self.collectionView reloadData], and the your collection view will reload itself (i.e. call numberOfItems and cellForItemAtIndexPath for each item).
In your UICollectionViewDataSource methods that return the number of sections and items, simply return 0 if the properties that hold your model are nil or empty.
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
// Correctly returns 0 if nil or empty.
return [self.releaseWeek count];
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
if(!self.releaseWeekDictionary[section] || !self.releaseWeek[section]) {
return 0;
}else{
return [self.releaseWeekDictionary[self.releaseWeek[section]] count];
}
}
Below should be the gravy code in your completion block.
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"#");
NSArray *upcomingReleasesArray = [dataDictionary objectForKey:#"upcoming_releases"];
//This is the dateFormatter we'll need to parse the release dates
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
NSTimeZone *est = [NSTimeZone timeZoneWithAbbreviation:#"EST"];
[dateFormatter setTimeZone:est];
[dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:#"en_US"]]; //A bit of an overkill to avoid bugs on different locales
//Temp array where we'll store the unsorted bucket dates
NSMutableArray *unsortedReleaseWeek = [[NSMutableArray alloc] init];
NSMutableDictionary *tmpDict = [[NSMutableDictionary alloc] init];
for (NSDictionary *upcomingReleaseDictionary in upcomingReleasesArray) {
//We find the release date from the string
NSDate *releaseDate = [dateFormatter dateFromString:[upcomingReleaseDictionary objectForKey:#"release_date"]];
//We create a new date that ignores everything that is not the actual day (ignoring stuff like the time of the day)
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components =
[gregorian components:(NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit) fromDate:releaseDate];
//This will represent our releases "bucket"
NSDate *bucket = [gregorian dateFromComponents:components];
//We get the existing objects in the bucket and update it with the latest addition
NSMutableArray *releasesInBucket = [tmpDict objectForKey:bucket];
if (!releasesInBucket){
releasesInBucket = [NSMutableArray array];
[unsortedReleaseWeek addObject:bucket];
}
UpcomingRelease *upcomingRelease = [UpcomingRelease upcomingReleaseWithName:[upcomingReleaseDictionary objectForKey:#"release_name"]];
upcomingRelease.release_date = [upcomingReleaseDictionary objectForKey:#"release_date"];
upcomingRelease.release_date = [upcomingReleaseDictionary objectForKey:#"release_date"];
[releasesInBucket addObject:upcomingRelease];
[tmpDict setObject:releasesInBucket forKey:bucket];
}
[unsortedReleaseWeek sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSDate* date1 = obj1;
NSDate* date2 = obj2;
//This will sort the dates in ascending order (earlier dates first)
return [date1 compare:date2];
//Use [date2 compare:date1] if you want an descending order
}];
self.releaseWeekDictionary = [NSDictionary dictionaryWithDictionary:tmpDict];
self.releaseWeek = [NSArray arrayWithArray:unsortedReleaseWeek];
[self.collectionView reloadData];
} failure:nil];
Edit: In your code, you were no longer assigning anything to upcomingReleases (block of commented code lines 91-102), and you were crashing referencing the index that didn't exist in the array. The fix is easy:
109: self.upcomingReleases = [dataDictionary objectForKey:#"upcoming_releases"];
122: for (NSDictionary *upcomingReleaseDictionary in self.upcomingReleases) {
I need to sort an NSArray containing time NSString's such as,
NSMutableArray *times = [[NSMutableArray alloc]initWithObjects:#"09:00 AM",#"07:30 AM",#"06:45 PM",#"05:00 PM",#"12:45 AM",#"12:45 PM",#"01:00 AM",#"01:15 PM", nil];
What I need is to sort the array in ascending order of time.
Is there any way to do such a thing?
NSMutableArray *times = [[NSMutableArray alloc]initWithObjects:#"09:00 AM",#"07:30 AM",#"06:45 PM",#"05:00 PM",#"12:45 AM",#"12:45 PM",#"01:00 AM",#"01:15 PM", nil];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"hh:mm a"];
NSArray *sortedTimes = [times sortedArrayUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2)
{
NSDate *date1 = [dateFormatter dateFromString:obj1];
NSDate *date2 = [dateFormatter dateFromString:obj2];
return [date1 compare:date2];
}];
optimized version:
NSMutableArray *times = [[NSMutableArray alloc]initWithObjects:#"09:00 AM",#"07:30 AM",#"06:45 PM",#"05:00 PM",#"12:45 AM",#"12:45 PM",#"01:00 AM",#"01:15 PM", nil];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"hh:mm a"];
NSMutableArray *dates = [NSMutableArray arrayWithCapacity:times.count];
for (NSString *timeString in times)
{
NSDate *date = [dateFormatter dateFromString:timeString];
[dates addObject:date];
}
[dates sortUsingSelector:#selector(compare:)];
NSMutableArray *sortedTimes = [NSMutableArray arrayWithCapacity:dates.count];
for (NSDate *date in dates)
{
NSString *timeString = [dateFormatter stringFromDate:date];
[sortedTimes addObject:timeString];
}
You can try this code:
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"hh:mm a"];
[times sortUsingComparator:^NSComparisonResult(NSString* obj1, NSString *obj2) {
NSDate *firstDate = [formatter dateFromString:obj1];
NSDate *secondDate = [formatter dateFromString:obj2];
return [firstDate compare:secondDate];
}];
As these are strings it will be sored as
01:15, 12:25, 05:00....
And they are not either NSDate.
So you need to do is that Create a parallel array having NSDate from these strings, sort the array, and extract these values.
While implementing I solved it by novice-way
NSMutableArray *times = [[NSMutableArray alloc]initWithObjects:#"09:00 AM",#"07:30 AM",#"06:45 PM",#"05:00 PM",#"12:45 AM",#"12:45 PM",#"01:00 AM",#"01:15 PM", nil];
NSMutableArray *dates=[NSMutableArray new];
NSDateFormatter *dateFormatter=[NSDateFormatter new];
[dateFormatter setDateFormat:#"hh:mm a"];
for (NSString *stringDate in times) {
NSDate *date=[dateFormatter dateFromString:stringDate];
[dates addObject:date];
}
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"self" ascending:YES];
NSArray *descriptors = [NSArray arrayWithObject: descriptor];
NSArray *reverseOrder = [dates sortedArrayUsingDescriptors:descriptors];
[times removeAllObjects];
for (NSDate *date in reverseOrder) {
NSString *string=[dateFormatter stringFromDate:date];
[times addObject:string];
}
NSLog(#"%#",times);
For NSDate Comparison use this:
+ (BOOL)isDate:(NSDate *)date1 smallerThanAnotherDate:(NSDate *)date2
{
NSDate* enddate = date1;
NSDate* currentdate = date2;
NSTimeInterval distanceBetweenDates = [enddate timeIntervalSinceDate:currentdate];
double secondsInMinute = 60;
NSInteger secondsBetweenDates = distanceBetweenDates / secondsInMinute;
if (secondsBetweenDates <= 0)
return YES;
else
return NO;
}
So If you do not want to convert your hours to NSDate do this alone it works for me
NSArray *sortedTimes = [times sortedArrayUsingSelector:#selector(localizedStandardCompare:)];