看了眼 tinyfool 经常提的日历控件

2016-11-27 18:49:43 +08:00
 EagleB

先贴上源码地址:Here 代码是是 08 年写的,这点还是非常服的,这个时候我还在上高中。 08 年到现在 OC 在一些特性上改进很多,其中使用的CFGregorianDate相关 api 在 iOS 8.0 之后也不建议使用了,所以这里我只说我确认不是好的实践的部分。

先来看下头文件:

//
//  CalendarView.h
//  ZhangBen
//
//  Created by tinyfool on 08-10-26.
//  Copyright 2008 __MyCompanyName__. All rights reserved.
//

#import <UIKit/UIKit.h>

@protocol CalendarViewDelegate;

@interface TdCalendarView : UIView {
	CFGregorianDate currentMonthDate;
	CFGregorianDate currentSelectDate;
	CFAbsoluteTime	currentTime;
	UIImageView* viewImageView;
	id<CalendarViewDelegate> calendarViewDelegate;
	int *monthFlagArray; 
}

@property CFGregorianDate currentMonthDate;
@property CFGregorianDate currentSelectDate;
@property CFAbsoluteTime  currentTime;

@property (nonatomic, retain) UIImageView* viewImageView;
@property (nonatomic, assign) id<CalendarViewDelegate> calendarViewDelegate;
-(int)getDayCountOfaMonth:(CFGregorianDate)date;
-(int)getMonthWeekday:(CFGregorianDate)date;
-(int)getDayFlag:(int)day;
-(void)setDayFlag:(int)day flag:(int)flag;
-(void)clearAllDayFlag;
@end



@protocol CalendarViewDelegate<NSObject>
@optional
- (void) selectDateChanged:(CFGregorianDate) selectDate;
- (void) monthChanged:(CFGregorianDate) currentMonth viewLeftTop:(CGPoint)viewLeftTop height:(float)height;
- (void) beforeMonthChange:(TdCalendarView*) calendarView willto:(CFGregorianDate) currentMonth;
@end

代码格式我就不说了,空格写的很随意,大小写对于我这种强迫症来说也很受不了。最重要的是我认为稍微参考下苹果 framework 中函数的命名方式,就不会写出协议中这么扯淡的命名。 interface 中的命名大多数都还不错,但是-(void)setDayFlag:(int)day flag:(int)flag;这个是什么鬼,我认为- (void)setFlag:(int)flag forDay:(int)day;更好。

下面来看下源文件:

源文件中定义了全局的几个变量:

const float headHeight=60;
const float itemHeight=35;
const float prevNextButtonSize=20;
const float prevNextButtonSpaceWidth=15;
const float prevNextButtonSpaceHeight=12;
const float titleFontSize=30;
const int	weekFontSize=12;

这几个变量主要是来控制试图的大小、字体的大小,只有在这个文件内部试哟哦难过,没有用static修饰,不是很明白,可能 tinyfool 记忆里好,不会再工程中其他地方使用相同名字的变量。

学 C 语言的时候,大概都做过这么一个练习:获取某年某月的天数。来看看 tinyfool 的实现:**

-(int)getDayCountOfaMonth:(CFGregorianDate)date{
	switch (date.month) {
		case 1:
		case 3:
		case 5:
		case 7:
		case 8:
		case 10:
		case 12:
			return 31;
			
		case 2:
			if((date.year % 4==0 && date.year % 100!=0) || date.year % 400==0)
				return 29;
			else
				return 28;
		case 4:
		case 6:
		case 9:		
		case 11:
			return 30;
		default:
			return 31;
	}
}

interesting ,自行体会一下。

实现中有很多类似的实践(个人认为这不是好的实践):

- (void)movePrevMonth{
	if(currentMonthDate.month>1)
		currentMonthDate.month-=1;
	else
	{
		currentMonthDate.month=12;
		currentMonthDate.year-=1;
	}
	[self movePrevNext:0];
}

再来看下这个类的析构函数:

- (void)dealloc {
    [super dealloc];
    free(monthFlagArray);
}

Excuse me. 这里虽然不太可能出现崩溃的情况,但不是应该先释放子类持有的资源?

最后,总结一些 tinyfool 的变量命名风格:title_MonthweekfonttabHeights_width


我观察到的是,如果有人在微博上反驳他什么,他通常的回应是毫无道理(有道理的时候也有,少),其他的不想评价,怕被喷。

8507 次点击
所在节点    程序员
63 条回复
acros
2016-11-27 21:23:17 +08:00
角度不太对。
评价软件应该看他优点多突出,对于净挑毛病的,应该没几个人有底气....
l0wkey
2016-11-27 21:27:46 +08:00
想起了 Dash 的 iOS 版
missdeer
2016-11-27 22:58:58 +08:00
@Allianzcortex 手机上只看到 date.year % 4==0 这一截。。。电脑上看到完整的没问题
kevinreadonly
2016-11-27 23:02:00 +08:00
@zonghua 恩,那个有钱的死胖子 2333333
xcodebuild
2016-11-27 23:29:07 +08:00
大家都看得出来你什么意思,即使你不停的说『没有别的意思』。
Sirormy
2016-11-28 00:42:46 +08:00
找上门来不好意思说了,哈哈哈哈哈
onlyhot
2016-11-28 00:51:25 +08:00
气氛有点怪
crisfun
2016-11-28 03:07:52 +08:00
若要补刀应该让我们见识下什么是经常提
daniellu
2016-11-28 08:16:55 +08:00
无可厚非啊,肯开源,就已经很了不起了。
挑毛病,谁不会,从头到尾的起一个控件、写好、开源啊,再说, ios 刚发布的那时候,国内连资料都很少,更加别说开源控件了。
有时间翻翻自己 N 年前写的代码呗,每个人都是在不停的成长的,对不对?
juice
2016-11-28 09:07:30 +08:00
@tinyfool 该续费了
tommyzhang
2016-11-28 09:17:05 +08:00
code review 别人几年前的代码 然后说 low 相信楼主不是傻逼 就是二百五脑袋被驴提过了
LedChang
2016-11-28 09:21:36 +08:00
我觉得楼主说的没毛病
LedChang
2016-11-28 09:22:37 +08:00
不知道你们在喷什么,看看当时的代码指出来有问题怎么了,谁不是一点点成长起来的
tinyfool
2016-11-28 09:40:00 +08:00
真的不是不能批评,不过,我觉得,做性能优化,我经验比楼主多多了,我就在多少两句吧。关于,那个不用查表,用 Switch-Case 的问题。

这么说话都是半瓶子咣当,性能优化不是教条,不是说,老师说这么写对的就这么写。性能优化是一个一直在变的东西,唯一可以相信的是 profile 。

第一,不要过早优化。
第二,这是一个有限条件选择,不涉及到问题增长速度。
第三,编译器如果觉得这里值得优化成一个 table 会动手的。
第四,性能优化,要理解一个代码调用频度场景。这个函数会被调用几次呢?大概,只在日历初始化的时候,调用一次,翻页的时候,调用一次。翻一次页,人工都设置了一个动画, 0.5 秒,还是多少记不得了。然而,这里用 Switch-Case 还是查表性能差异可能对产品性能产生影响么?

写代码的时候,第一优先是可读性。这个代码其实可读性也一般,因为说过了,基本上就是一晚上随手写的,后来也没改过。性能一定要在 profile 的前提下去做。我们的学校教育,教育出来一堆纸上谈兵的性能知识,很多还是错的。比如很多类似的技巧,在编译器优化前提下,根本不存在了。比如当年谭浩强的书里面给你讲了一堆,在某个编译器可能成成立,在另外一个编译器不能成立的技巧。

我不是说,我这么说一定比查表好。而是,这不是你该关心的问题。如果 profile 说明这里是一个性能攸关点,你做各种尝试都是合理的。在这时候,我觉得想太多。跟讨论回有几个写法差不多。
imsoso
2016-11-28 09:51:26 +08:00
好久没见到楼主活人了, mark 一记
muziki
2016-11-28 09:57:08 +08:00
Year & 3 == 0 && ( year % 25 != 0 || year & 15 == 0)
判断闰年会快一些
hotdogwc
2016-11-28 09:58:15 +08:00
虽然不爱被灌鸡汤,但是讲道理,刚才把代码看了一遍, SDK 发布几个月,资料各种缺失的情况下写出这个东西,我是服的。我觉得“没别的意思”的人应该想想在那个情景下是不是可以写的比这个好,反正我不能。
greatghoul
2016-11-28 10:00:08 +08:00
楼主你其实是嫉妒人家有个漂亮可爱的女朋友而已吧。。
hotdogwc
2016-11-28 10:00:49 +08:00
@l0wkey Dash 代码我也草草的看了一遍,没看到什么槽点,难道我的代码洁癖严重不足?
htfy96
2016-11-28 10:02:35 +08:00
为什么 getDayOfMonth 一定要查表,感觉这么写也挺清晰的

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/323650

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX