From 0446f9febfefe6acca651f34767d60fef5349886 Mon Sep 17 00:00:00 2001 From: WenchaoIOS Date: Sun, 8 Nov 2015 09:13:09 +0800 Subject: [PATCH] NSDateComponents sharedInstance 1. Make NSDateComponents in NSDate+FSExtension.h single instance, avoid alloc every time using it. This makes performance better 2. Optimize other logic --- Example/AppDelegate.m | 2 - Example/StoryboardExampleViewController.m | 2 +- FSCalendar/FSCalendar.m | 90 ++++++++++++----------- FSCalendar/NSDate+FSExtension.m | 37 +++++++--- 4 files changed, 75 insertions(+), 56 deletions(-) diff --git a/Example/AppDelegate.m b/Example/AppDelegate.m index aac9a60..7eb4433 100644 --- a/Example/AppDelegate.m +++ b/Example/AppDelegate.m @@ -7,14 +7,12 @@ // #import "AppDelegate.h" -#import "FScalendar.h" @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. - return YES; } diff --git a/Example/StoryboardExampleViewController.m b/Example/StoryboardExampleViewController.m index b80c0f8..5730b17 100644 --- a/Example/StoryboardExampleViewController.m +++ b/Example/StoryboardExampleViewController.m @@ -130,7 +130,7 @@ - (void)calendarCurrentPageDidChange:(FSCalendar *)calendar { NSLog(@"did change to page %@",[calendar.currentPage fs_stringWithFormat:@"MMMM yyyy"]); - [calendar selectDate:calendar.currentPage]; +// [calendar selectDate:calendar.currentPage]; } - (void)calendarCurrentScopeWillChange:(FSCalendar *)calendar animated:(BOOL)animated diff --git a/FSCalendar/FSCalendar.m b/FSCalendar/FSCalendar.m index 0649ca1..8aaeadc 100644 --- a/FSCalendar/FSCalendar.m +++ b/FSCalendar/FSCalendar.m @@ -477,19 +477,22 @@ } return NO; } - if ([collectionView.indexPathsForSelectedItems containsObject:indexPath] || [_selectedDates containsObject:[self dateForIndexPath:indexPath]]) { + NSDate *targetDate = [self dateForIndexPath:indexPath]; + if ([self isDateSelected:targetDate]) { + // 这个if几乎不会调用到 if (self.allowsMultipleSelection) { if ([self collectionView:collectionView shouldDeselectItemAtIndexPath:indexPath]) { [collectionView deselectItemAtIndexPath:indexPath animated:YES]; [self collectionView:collectionView didDeselectItemAtIndexPath:indexPath]; } } else { + // 点击了已经选择的日期,直接触发事件 [self didSelectDate:self.selectedDate]; } return NO; } BOOL shouldSelect = YES; - if (shouldSelect && cell.date && [self isDateInRange:cell.date] && !_supressEvent) { + if (cell.date && [self isDateInRange:cell.date] && !_supressEvent) { shouldSelect &= [self shouldSelectDate:cell.date]; } if (shouldSelect) { @@ -516,6 +519,7 @@ } NSDate *selectedDate = cell.date ?: [self dateForIndexPath:indexPath]; [_selectedDates removeObject:selectedDate]; + [self deselectCounterpartDate:selectedDate]; [self didDeselectDate:selectedDate]; } @@ -1182,60 +1186,62 @@ if (![self isDateInRange:date]) { [NSException raise:@"selectedDate out of range" format:@""]; } - NSDate *targetDate = [date fs_daysFrom:_minimumDate] < 0 ? _minimumDate.copy : date; - targetDate = [targetDate fs_daysFrom:_maximumDate] > 0 ? _maximumDate.copy : targetDate; - targetDate = targetDate.fs_dateByIgnoringTimeComponents; + NSDate *targetDate = date.fs_dateByIgnoringTimeComponents; NSIndexPath *targetIndexPath = [self indexPathForDate:targetDate]; BOOL shouldSelect = !_supressEvent; + // 跨月份点击 if (forPlaceholder) { - // 跨月份选中日期,需要触发各类事件 - if (self.allowsMultipleSelection && [self isDateSelected:targetDate]) { - // 在多选模式下,点击了已经选中的跨月日期 - BOOL shouldDeselect = [self shouldDeselectDate:targetDate]; - if (!shouldDeselect) { + if (self.allowsMultipleSelection) { + // 处理多选模式 + if ([self isDateSelected:targetDate]) { + BOOL shouldDeselect = [self shouldDeselectDate:targetDate]; + if (!shouldDeselect) { + return; + } + } else { + shouldSelect &= [self shouldSelectDate:targetDate]; + if (!shouldSelect) { + return; + } + } + } else { + // 处理单选模式 + shouldSelect &= [self shouldSelectDate:targetDate]; + if (shouldSelect) { + if ([self isDateSelected:targetDate]) { + [self didSelectDate:targetDate]; + } else { + NSDate *selectedDate = self.selectedDate; + if (selectedDate) { + [self deselectDate:selectedDate]; + } + [_collectionView selectItemAtIndexPath:targetIndexPath animated:YES scrollPosition:UICollectionViewScrollPositionNone]; + [self collectionView:_collectionView didSelectItemAtIndexPath:targetIndexPath]; + } + } else { return; } } - shouldSelect &= [self shouldSelectDate:targetDate]; - if (shouldSelect && ![self isDateSelected:targetDate]) { - if (_collectionView.indexPathsForSelectedItems.count && self.selectedDate && !self.allowsMultipleSelection) { - NSIndexPath *currentIndexPath = [self indexPathForDate:self.selectedDate]; - [_collectionView deselectItemAtIndexPath:currentIndexPath animated:YES]; - [self deselectCounterpartDate:self.selectedDate]; - [self collectionView:_collectionView didDeselectItemAtIndexPath:currentIndexPath]; - } - if ([self collectionView:_collectionView shouldSelectItemAtIndexPath:targetIndexPath]) { - [_collectionView selectItemAtIndexPath:targetIndexPath animated:YES scrollPosition:UICollectionViewScrollPositionNone]; - [self collectionView:_collectionView didSelectItemAtIndexPath:targetIndexPath]; - } - } else { - [self didSelectDate:targetDate]; - } - } else if (![_selectedDates containsObject:targetDate]){ - // 手动选中日期时,需先反选已经选中的日期,但不触发事件 + + } else if (![self isDateSelected:targetDate]){ + // 调用代码选中未选中日期 if (self.selectedDate && !self.allowsMultipleSelection) { - NSDate *selectedDate = self.selectedDate; - NSIndexPath *currentIndexPath = [self indexPathForDate:selectedDate]; - [_collectionView deselectItemAtIndexPath:currentIndexPath animated:NO]; - FSCalendarCell *cell = (FSCalendarCell *)[_collectionView cellForItemAtIndexPath:currentIndexPath]; - cell.dateIsSelected = NO; - [cell setNeedsLayout]; - [_selectedDates removeObject:selectedDate]; - [self deselectCounterpartDate:selectedDate]; + [self deselectDate:self.selectedDate]; } [_collectionView selectItemAtIndexPath:targetIndexPath animated:YES scrollPosition:UICollectionViewScrollPositionNone]; - FSCalendarCell *cell = (FSCalendarCell *)[_collectionView cellForItemAtIndexPath:targetIndexPath]; [cell performSelecting]; [self enqueueSelectedDate:targetDate]; [self selectCounterpartDate:targetDate]; } else if (![_collectionView.indexPathsForSelectedItems containsObject:targetIndexPath]) { + // 调用代码选中以选中日期 [_collectionView selectItemAtIndexPath:targetIndexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone]; } if (scrollToDate) { + // 如果跨月份点击日期,并且该日期不应该选中,则不跳转页面,其他情况均跳转 if (forPlaceholder && !shouldSelect) { return; } @@ -1275,7 +1281,7 @@ } } - if (_pagingEnabled) { + if (!self.floatingMode) { switch (_collectionViewLayout.scrollDirection) { case UICollectionViewScrollDirectionVertical: { @@ -1292,16 +1298,18 @@ } } else { - CGRect itemFrame = [_collectionViewLayout layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:scrollOffset]].frame; - if (self.floatingMode && CGRectEqualToRect(itemFrame, CGRectZero)) { + // 全屏模式中,切换页面时需要将该月份提升到视图最上方 + CGRect headerFrame = [_collectionViewLayout layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:scrollOffset]].frame; + if (CGSizeEqualToSize(headerFrame.size, CGSizeZero)) { + // 如果在loadView或者viewDidLoad中调用需要切换月份的方法, 这时UICollectionView并没有准备好自己的单元格和空间大小,这时不能直接调用setContentOffset,而是等到在layoutSubviews之后再去调用 _currentPage = targetDate; _needsAdjustingMonthPosition = YES; [self setNeedsLayout]; } else { - CGRect headerFrame = [_collectionViewLayout layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:scrollOffset]].frame; CGPoint targetOffset = CGPointMake(0, MIN(headerFrame.origin.y,_collectionView.contentSize.height-_collectionView.fs_bottom)); [_collectionView setContentOffset:targetOffset animated:animated]; } + } if (_header && !animated) { @@ -1335,7 +1343,7 @@ } [self didChangeValueForKey:@"currentPage"]; [self scrollToDate:_currentPage animated:animated]; - } else if (!_pagingEnabled) { + } else { [self scrollToDate:date.fs_firstDayOfMonth animated:animated]; } } diff --git a/FSCalendar/NSDate+FSExtension.m b/FSCalendar/NSDate+FSExtension.m index 24d7049..8740785 100644 --- a/FSCalendar/NSDate+FSExtension.m +++ b/FSCalendar/NSDate+FSExtension.m @@ -99,11 +99,12 @@ { NSCalendar *calendar = [NSCalendar fs_sharedCalendar]; NSDateComponents *weekdayComponents = [calendar components:NSCalendarUnitWeekday fromDate:self]; - NSDateComponents *componentsToSubtract = [[NSDateComponents alloc] init]; + NSDateComponents *componentsToSubtract = [NSDateComponents fs_sharedDateComponents]; componentsToSubtract.day = - (weekdayComponents.weekday - calendar.firstWeekday); NSDate *beginningOfWeek = [calendar dateByAddingComponents:componentsToSubtract toDate:self options:0]; NSDateComponents *components = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay fromDate:beginningOfWeek]; beginningOfWeek = [calendar dateFromComponents:components]; + componentsToSubtract.day = NSIntegerMax; return beginningOfWeek; } @@ -142,19 +143,25 @@ + (instancetype)fs_dateWithYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day { NSCalendar *calendar = [NSCalendar fs_sharedCalendar]; - NSDateComponents *components = [[NSDateComponents alloc] init]; + NSDateComponents *components = [NSDateComponents fs_sharedDateComponents]; components.year = year; components.month = month; components.day = day; - return [calendar dateFromComponents:components]; + NSDate *date = [calendar dateFromComponents:components]; + components.year = NSIntegerMax; + components.month = NSIntegerMax; + components.day = NSIntegerMax; + return date; } - (NSDate *)fs_dateByAddingYears:(NSInteger)years { NSCalendar *calendar = [NSCalendar fs_sharedCalendar]; - NSDateComponents *components = [[NSDateComponents alloc] init]; + NSDateComponents *components = [NSDateComponents fs_sharedDateComponents]; components.year = years; - return [calendar dateByAddingComponents:components toDate:self options:0]; + NSDate *date = [calendar dateByAddingComponents:components toDate:self options:0]; + components.year = NSIntegerMax; + return date; } - (NSDate *)fs_dateBySubtractingYears:(NSInteger)years @@ -165,9 +172,11 @@ - (NSDate *)fs_dateByAddingMonths:(NSInteger)months { NSCalendar *calendar = [NSCalendar fs_sharedCalendar]; - NSDateComponents *components = [[NSDateComponents alloc] init]; + NSDateComponents *components = [NSDateComponents fs_sharedDateComponents]; components.month = months; - return [calendar dateByAddingComponents:components toDate:self options:0]; + NSDate *date = [calendar dateByAddingComponents:components toDate:self options:0]; + components.month = NSIntegerMax; + return date; } - (NSDate *)fs_dateBySubtractingMonths:(NSInteger)months @@ -178,9 +187,11 @@ - (NSDate *)fs_dateByAddingWeeks:(NSInteger)weeks { NSCalendar *calendar = [NSCalendar fs_sharedCalendar]; - NSDateComponents *components = [[NSDateComponents alloc] init]; + NSDateComponents *components = [NSDateComponents fs_sharedDateComponents]; components.weekOfYear = weeks; - return [calendar dateByAddingComponents:components toDate:self options:0]; + NSDate *date = [calendar dateByAddingComponents:components toDate:self options:0]; + components.weekOfYear = NSIntegerMax; + return date; } -(NSDate *)fs_dateBySubtractingWeeks:(NSInteger)weeks @@ -191,9 +202,11 @@ - (NSDate *)fs_dateByAddingDays:(NSInteger)days { NSCalendar *calendar = [NSCalendar fs_sharedCalendar]; - NSDateComponents *components = [[NSDateComponents alloc] init]; - [components setDay:days]; - return [calendar dateByAddingComponents:components toDate:self options:0]; + NSDateComponents *components = [NSDateComponents fs_sharedDateComponents]; + components.day = days; + NSDate *date = [calendar dateByAddingComponents:components toDate:self options:0]; + components.day = NSIntegerMax; + return date; } - (NSDate *)fs_dateBySubtractingDays:(NSInteger)days