我有一个DiningHall类,它有3个属性:openingTime、closingTime和nextMealOpeningTime,我需要从这个网站的数据中设置这些NSDate属性。
每个DiningHall对象对应于特定的套餐。例如,有一个单独的"De Neve“餐厅对象早餐,午餐和晚餐。
作为一个例子,如果我有一个与“午餐”相对应的De Neve hall对象,那么“时代”是
早餐(9-11)午餐(12-2)晚餐(5-8)
然后openingTime是12点,closingTime是2点,nextMealOpeningTime是5点。
一般的算法是:
给定一顿饭:对于数据中的每个大厅,查找与当前膳食解析文本对应的hall查找列,将toNSDate传递3 NSDate的数组转换为DiningHall。
我正在使用开源DOM解析器,下面是提取文本的代码,一旦我得到正确的行。特定的关注点是处理“封闭”膳食,以及将数据传递给DiningHall类的更好方法,但是任何优化都会有所帮助。
- (NSArray*) getHourDataForRow:(TFHppleElement*)row Meal:(NSString*)meal {
NSArray *meals = [row childrenWithTagName:@"td"];
NSArray *mealNames = [NSArray arrayWithObjects:@"breakfast", @"lunch", @"dinner", nil];
int index = [mealNames indexOfObject:meal]+1;
TFHppleElement *cell = meals[index];
NSArray *strong = [cell childrenWithTagName:@"strong"];
NSMutableArray *retArr = [NSMutableArray array];
NSString *opening = [strong[0] firstChildWithTagName:@"text"].content;
NSDate *openingAsDate = [self dateFromString:opening];
if (openingAsDate){
[retArr addObject:openingAsDate];
NSString *closing = [strong[1] firstChildWithTagName:@"text"].content;
[retArr addObject:[self dateFromString:closing]];
}
else{
[retArr addObject:[NSNull null]];
[retArr addObject:[NSNull null]];
}
if (index +1 <= 3) {
TFHppleElement *nextCell = meals[index+1];
NSArray *strong1 = [nextCell childrenWithTagName:@"strong"];
NSString* nextOpening = [strong1[0] firstChildWithTagName:@"text"].content; //strong[0] is opening time, don't need closing time from next cell
[retArr addObject:[self nextOpening.content]];
}
else // nextMealOpeningTime is always nil for dinner
[retArr addObject:[NSNull null]];
return retArr;
}
- (NSDate*) dateFromString:(NSString*)time {
if ([time isEqualToString:@"CLOSED"])
return nil;
NSArray *digits = [time componentsSeparatedByCharactersInSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]];
int hour = [digits[0] intValue];
hour+= (([time rangeOfString:@"pm"].location == NSNotFound) ? 0:12) ; //add 12 for pm
int minutes = [digits[1] intValue];
//format nsdate
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [calendar components:( NSYearCalendarUnit | NSMonthCalendarUnit | NSWeekCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit ) fromDate:[NSDate date]];
[components setHour:hour];
[components setMinute:minutes];
return [calendar dateFromComponents:components];
}- (void) setHoursFromData:(NSArray*)data {
if (data[0] != [NSNull null] && data[1] != [NSNull null]){
_openingTime = data[0];
_closingTime = data[1];
}
if (data[2] != [NSNull null])
_nextOpeningTime = data[2];
}发布于 2014-08-07 03:47:21
我想我可以谈谈一些命名问题,以及DiningHall类中的一些逻辑。我不知道你是否会回来检查你的问题是否有额外的答案,但也许这会对其他人有所帮助。
下面是您编写的方法:
- (void) setHoursFromData:(NSArray*)data {
if (data[0] != [NSNull null] && data[1] != [NSNull null]){
_ openingTime = data[0];
_closingTime = data[1];
}
if (data[2] != [NSNull null])
_nextOpeningTime = data[2];
}nhgrif已经指出,您有不规则的缩进和间距,应该始终在if语句周围使用大括号,但是这些事情值得重复,因为它们极大地提高了代码的可读性。
让我们来谈谈方法名setHoursFromData:(NSArray*)data。首先,除非这是一个属性,并且您正在为它创建一个手动设置器,否则调用方法“set.”是不正确的命名。我可以看到你在这里设置多个象牙,所以我可以理解你为什么会选择这个名字,但它仍然令人困惑,因为它让我觉得你在设置一个属性。第二件事是,从名称上看,根本不清楚数据是什么,也不清楚如何使用它来设置时间。简单地描述数据是什么就更有意义了。我不是专家,但我可以称之为configureHoursForOpenCloseTimes。当然,它更长,但它使代码更多的自我记录。
同样的建议也适用于getHourDataForRow,它看起来像一个属性获取器。我想这和hourDataForRow一样好。
现在要在方法内移动。当您简单地以您所做的方式访问data[0]和data[1]时,它会使该值中包含的内容变得不清楚。这使我认为在这种情况下使用NSArray并不是可读性的最佳选择。也许您应该传入一个包含openingTime、closingTime和nextOpeningTime属性的对象。你把它们都传递到一起,它们各自负责一个不同的信息。这还可以消除NSNull在这里可能出现的奇怪用法。(至少我觉得这似乎很奇怪?)完成此操作后,代码将类似于:
if (times.openingTime && times.closingTime) {
_openingTime = times.openingTime;
_closingTime = times.closingTime;
}我认为这是更易读的。但是,一旦将其转换为对象,就可能有更好的方法作为一个整体来处理这个问题。
我也不喜欢在if语句不正确的情况下什么都不会发生。如果它们不是真的,会发生什么?这在屏幕上是如何表示的?上面写的是“无效”还是别的什么?也许应该显示错误信息?也没有什么能阻止这三个值成为真。那么,是否有三个点,当数据为空时,它是否只显示一个空白点?从代码中看,这一切都不明显。这让我怀疑是否清除了_openingTime和_closingTime的旧值,或者如果数据为null,它是否只是显示错误的时间。
有更多的问题,但这足以进行一次审查。
发布于 2014-07-24 22:46:02
现在,我将避免过多地评论- (NSArray*) getHourDataForRow:(TFHppleElement*)row Meal:(NSString*)meal,因为我认为这里的真正答案是查看NSXMLParser,看看它是否适用于您。除此之外,我现在简单地评论一下,您的间距是不一致的,您应该进行清理,以提高代码的可读性。
不过,我将对dateFromString:发表评论
- (NSDate*) dateFromString:(NSString*)time {
if ([time isEqualToString:@"CLOSED"])
return nil;
NSArray *digits = [time componentsSeparatedByCharactersInSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]];
int hour = [digits[0] intValue];
hour+= (([time rangeOfString:@"pm"].location == NSNotFound) ? 0:12) ; //add 12 for pm
int minutes = [digits[1] intValue];
//format nsdate
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [calendar components:( NSYearCalendarUnit | NSMonthCalendarUnit | NSWeekCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit ) fromDate:[NSDate date]];
[components setHour:hour];
[components setMinute:minutes];
return [calendar dateFromComponents:components];
}首先,您在if语句中留下了方括号。这与笨拙的缩进结合在一起,使代码非常混乱。尽管是可选的,但绝不能省略花括号。
然而,方法的其余部分.完全可以被取代。有一个名为NSDateFormatter的类,它专门用于将NSDate对象转换为NSString对象,反之亦然。
首先,我们需要此链接。这让我们知道我们的日期格式字符串应该是什么样子。我们有小时没有前导零,在12小时格式,分钟,我们有分钟,我们有一个上午/下午的符号。
所以我们的格式字符串将如下所示:
@"h:mma"我们的AM符号是@"am",PM符号是@"pm"。现在,我们有了创建NSDateFormatter对象所需的所有信息:
- (NSDate*) dateFromString:(NSString*)time {
if ([time isEqualToString:@"CLOSED"]) {
return nil;
} else {
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:@"h:mma"];
[df setAMSymbol:@"am"];
[df setPMSymbol:@"pm"];
return [df dateFromString:time];
}
}https://codereview.stackexchange.com/questions/57795
复制相似问题