需求
這兩個(gè)獲取一個(gè)需求,需要做一個(gè)打卡列表,顯示上個(gè)月所有打卡的信息,及這個(gè)月到今天的的打卡信息,并且標(biāo)注出來(lái)月份。設(shè)計(jì)界面大致如此:

需求圖片
后臺(tái)接口只能返回已經(jīng)打卡的信息。如果當(dāng)天沒(méi)有打卡,是不返回的。
//接口返回?cái)?shù)據(jù)結(jié)構(gòu)
"data": [
{
"signLastTime": 1522199821084, //當(dāng)天最后一次打卡時(shí)間
"signMonth": 3, //當(dāng)天屬于幾月
"week": "周三", //當(dāng)天屬于周幾
"inDate": 1522199817934, //數(shù)據(jù)庫(kù)返回時(shí)間,本地?zé)o用
"signDay": 28, //當(dāng)天屬于幾號(hào)
"signItems": [ //當(dāng)天打卡次數(shù),返回每次打卡數(shù)據(jù)
{
"longitude": 123566, //經(jīng)度
"signAdress": "北京市海淀區(qū)上地地鐵口", //地址
"signTime": 1522199817934, //打卡時(shí)間
"latitude": 456233 //緯度
},
{
"longitude": 456233,
"signAdress": "北京市海淀區(qū)西直門(mén)地鐵口",
"signTime": 1522199821084,
"latitude": 123566
}
],
"reDate": 1522199821084, //數(shù)據(jù)庫(kù)返回時(shí)間,無(wú)用
"signYear": 2018, //本次打卡數(shù)據(jù)年份
"id": "5abaed0923130b394c1e10ce", //id
"signFirstTime": 1522199817934, //當(dāng)天首次打卡時(shí)間
"userId": 111225, //打卡人id
"status": 1 //客戶(hù)端無(wú)用
}
大家可以先不看我的解決方法,自己思考一下如何來(lái)寫(xiě)這個(gè)算法,才能達(dá)到最優(yōu)。
我的解決方案
聲明一下,我的解決方案可能不是最優(yōu)的,如果有好的想法,我們?cè)诹粞钥梢砸黄鹩懻摗?/p>
- 按照后臺(tái)接口返回,創(chuàng)建model類(lèi)。
- 創(chuàng)建一個(gè)config類(lèi),通過(guò)后臺(tái)返回?cái)?shù)據(jù),返回能被tableView解析顯示的數(shù)據(jù)。
config作為配置類(lèi),所有的算法配置寫(xiě)在這個(gè)類(lèi)中。類(lèi)大概是
思路:
- 通過(guò)獲取當(dāng)月到今天的天數(shù) currentMonthDay,在獲取上個(gè)月總天數(shù)lastMonthDay。
- 使用for循環(huán)來(lái)循環(huán),次數(shù) = currentMonthDay + lastMonthDay, 來(lái)生成一個(gè)只包含'yyyy-MM-dd'字符串類(lèi)型的數(shù)組【數(shù)組A】,生成一個(gè)字典包含key: 是上面的字符串,value:model的類(lèi)【字典A】
- 使用for循環(huán), 次數(shù) = punchList.count ,已經(jīng)打卡的天數(shù)。再通過(guò)打卡時(shí)某一天,替換上面字典A中的value:model值。
- 通過(guò)for循環(huán)【數(shù)組A】,來(lái)獲取【字典A】中的model值,生成一個(gè)新的數(shù)組【數(shù)組B】。使用這一步主要是確保時(shí)間的順序。
- 返回【數(shù)組B】就是需要的這兩個(gè)月的打卡數(shù)據(jù)model數(shù)組
6 通過(guò)在index = 0處插入當(dāng)月的月份,在 index = currentMonthDay +1 處插入上個(gè)月的月份。就生成了需要的結(jié)果。
結(jié)果類(lèi)型
{
monthStr = 4;
},
<NTOutdoorPunchInfoModel: 0x10eb40830>,
<NTOutdoorPunchInfoModel: 0x10eb3f6b0>,
<NTOutdoorPunchInfoModel: 0x10eb1da40>,
{
monthStr = 3;
},
<NTOutdoorPunchInfoModel: 0x10ec4e810>,
<NTOutdoorPunchInfoModel: 0x10ec1dc40>,
<NTOutdoorPunchInfoModel: 0x108896f00>,
......
上代碼
//config.m
@property (nonatomic, strong)NSMutableDictionary *monthDicInfo;
//public 對(duì)外放開(kāi)接口的類(lèi),主要是來(lái)配置解析數(shù)據(jù)的方法
- (NSArray *)configForPunchList:(NSArray *)punchList {
// 1. 首先創(chuàng)建返回解析好的數(shù)組,作為返回值返回
NSMutableArray *monthInfo = [[NSMutableArray alloc] init];
//2. 調(diào)用getMonthList 來(lái)獲取一個(gè)數(shù)組(備注1)和一個(gè)字典(備注2)
NSArray *monthList = [self getMonthList];
//3. for 循環(huán) 服務(wù)器返回的數(shù)據(jù),來(lái)更
for (NSDictionary *dic in punchList) {
NTOutdoorPunchInfoModel *model = [NTOutdoorPunchInfoModel getModelFromDic:dic];
NSTimeInterval firstTimePunch = model.signFirstTime;
NSString *timeStr = [TimeUtil getDateStr:firstTimePunch/1000];
[self.monthDicInfo setValue:model forKey:timeStr];
}
//4. 確定今天是幾月,通過(guò)今天是幾月,得出上個(gè)月是幾月,設(shè)置保存上個(gè)月的一個(gè)字典
NSInteger nowMonthInt = [self getYearOrMonthOrDayForDate:[NSDate date] calendarUnit:NSCalendarUnitMonth];
NSInteger lastMonthInt = (nowMonthInt == 1) ? 12 : nowMonthInt -1;
NSDictionary *nowMonthDic = @{@"monthStr":[NSString stringWithFormat:@"%ld",(long)nowMonthInt]};
NSDictionary *lastMonthDic = @{@"monthStr":[NSString stringWithFormat:@"%ld",(long)lastMonthInt]};
[monthInfo addObject:nowMonthDic];
// 5. for循環(huán)備注1的數(shù)組,通過(guò)key值,順序獲取備注2中的model值,保存到monthInfoList
for (NSString *timeStr in monthList) {
NTOutdoorPunchInfoModel *model = [self.monthDicInfo objectForKey:timeStr];
[monthInfo addObject:model];
}
//6. 確定幾天是幾號(hào),在monthInfoList插入到index = nowDay + 1數(shù)組中去
NSInteger nowDay = [self getYearOrMonthOrDayForDate:[NSDate date] calendarUnit:NSCalendarUnitDay];
[monthInfo insertObject:lastMonthDic atIndex:nowDay + 1];
return monthInfo;
//7. 返回配置好的
return monthInfoList
}
//private
//返回一個(gè)字符串?dāng)?shù)組,數(shù)組包括從當(dāng)天開(kāi)始到上個(gè)月1號(hào)的日期,格式y(tǒng)yyy-MM-dd
//并且創(chuàng)建了一個(gè)字典,key是yyyy-MM-dd的日期字符串,value是model類(lèi)
- (NSMutableArray *)getMonthList {
NSMutableArray *monthList = [[NSMutableArray alloc] init];
NSDate *currentDate = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd"];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *lastMonthComps = [[NSDateComponents alloc] init];
//當(dāng)月現(xiàn)在是幾日
NSInteger nowDay = [self getYearOrMonthOrDayForDate:[NSDate date] calendarUnit:NSCalendarUnitDay];
NSInteger lastMonthDays = [self getDaysWithLastMonth];
int count = 0;
for (NSInteger i = nowDay+lastMonthDays; i > 0; i --) {
// [lastMonthComps setYear:1]; // year = 1表示1年后的時(shí)間 year = -1為1年前的日期,month day 類(lèi)推
[lastMonthComps setDay:-count];
NSDate *newdate = [calendar dateByAddingComponents:lastMonthComps toDate:currentDate options:0];
NSString *dateStr = [formatter stringFromDate:newdate];
[monthList addObject:dateStr];
//保存每個(gè)model
NTOutdoorPunchInfoModel *model = [[NTOutdoorPunchInfoModel alloc] init];
model.signYear = [NSString stringWithFormat:@"%ld",(long)[self getYearOrMonthOrDayForDate:newdate calendarUnit:NSCalendarUnitYear]];
model.signMonth = [NSString stringWithFormat:@"%ld",(long)[self getYearOrMonthOrDayForDate:newdate calendarUnit:NSCalendarUnitMonth]];
model.signDay = [NSString stringWithFormat:@"%ld",(long)[self getYearOrMonthOrDayForDate:newdate calendarUnit:NSCalendarUnitDay]];
model.week = [self getWeekStrForDate:newdate];
[self.monthDicInfo setValue:model forKey:dateStr];
count++;
}
return monthList;
}
//private
//通過(guò)一個(gè)日期字符串返回date
- (NSDate *)getDateWithDateStr:(NSString *)str {}
//private
//獲取上個(gè)月有多少天
- (NSInteger)getDaysWithLastMonth {}
//private
//根據(jù)date日期,和calendarUnit返回date屬于哪一年,月,日
- (NSInteger)getYearOrMonthOrDayForDate:(NSDate *)date calendarUnit:(NSCalendarUnit)unit {
}
//private
//根據(jù)date日期獲取是周幾,轉(zhuǎn)化為例如'星期天' 表達(dá)
- (NSString *)getWeekStrForDate:(NSDate *)date {}
結(jié)尾:
可以?xún)?yōu)化的地方:如果當(dāng)天多次進(jìn)入到這個(gè)頁(yè)面,可以把獲取的【數(shù)組A】【字典A】緩存一下,每次進(jìn)來(lái)查看【數(shù)組A】首條是否是當(dāng)天,如果是當(dāng)天直接使用,不用走第二步,節(jié)省點(diǎn)計(jì)算時(shí)間。