看了眼 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


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

8506 次点击
所在节点    程序员
63 条回复
Lonely
2016-11-27 19:05:05 +08:00
你是说那个整天讲鸡汤的那个胖子吗
missdeer
2016-11-27 19:27:35 +08:00
求闰年的算法好像错了
acoder2013
2016-11-27 19:27:43 +08:00
tiny fool 是小笨蛋?
EagleB
2016-11-27 19:28:25 +08:00
@Lonely 嗯,是
Nexvar
2016-11-27 19:46:26 +08:00
技术圈有点小知名度的,有干货的还是不多
zonghua
2016-11-27 19:49:34 +08:00
@Nexvar 有个小女友的那位?
miao1007
2016-11-27 20:03:56 +08:00
买了那本书,感觉鸡汤感太浓
tinyfool
2016-11-27 20:05:36 +08:00
之前其实 V2EX 吐槽这个控件的人还蛮多。不过我很久不怎么上 V2EX ,甚至有时候搜索东西的时候,偶然发现自己被长篇大论的批判了一番都不知道,所以也都没回应。当然,之前包括吐槽这个插件的人,也都是一句话说写得烂,我也不知道该咋回应,所以,看到了也只好由他去了。

既然你这么认真的写,我就聊两句。

我写过一篇文章,其实提到过这个插件的前因后果,楼主包括其他人也都说我经常提到这个插件。没错,提过很多次,我好像没有说过这个东西有多牛逼。我只是说,在那个时候,大概是 IOS SDK 发布了几个月以后,没有啥日历插件可用,我就做了一个。

刚有 SDK 的时候,我其实并没有 iOS 设备,虽然很喜欢,但是确实买不起 iPhone ,很多人可能也记得当年 iPhone 其实也并不好买,那时候国内还没有行货呢。我的一个朋友的公司的活动上,抽奖,偏向我让我得到了一个 iPod touch 。我就想写个东西,写啥呢,就想写个记账软件,毕竟月月月光,也希望可以存点钱。设计的思路是首页有个日历,来显示最近一个月啥时候有收支。所以,就需要一个日历控件,当时并没有。就大概花了一个晚上做了一个吧。现在找不到原始的代码库, Google Code 的代码库好像也看不了修改历史了。细节我记得不了,反正这就是一个晚上或者几个晚上搞出来的东西,我那时候的主业是做搜索,基于 lucene 。

后来,做了两个星期,也就是学 iOS 两个星期后,有个大概样子了。这时候有道词典的人,通过新浪的一个朋友,找到了霍炬,辗转找到了我。他们当时想迅速做一个 iOS 版本占领市场,当时好像金山已经发了版本。但是有道那边,没有有 Mac/iOS 经历的工程师。于是我就答应帮他们做。

然后,做了一个月上线。我自己的记账软件就搁置了,一直到了 2013 年,我在上海的时候,才想起来,有这么一个搁置了多年的软件,找我的 CTO 补了个结尾,修改了一点 UI ,就上架了。以前有文章写过这个故事。

这个代码,我没记错的话,就是闰年有个 bug 改过一次,发布过就没改过了。
watzds
2016-11-27 20:14:05 +08:00
😮
tinyfool
2016-11-27 20:16:06 +08:00
好,说说代码风格。

我代码风格一般。写这个代码的时候,我日常写三种语言, Java , Php 和 OC 。代码风格混合,混乱肯定是有的。这个锅我的,我背。总体上是准备走 Apple 风格的,某些部分懒得改了,估计就比较乱了。

const 是常量,不是变量,不过这里确实比较没有怎么考虑。一开始是没准备开源的,做完了就直接开了。这锅也是我的。

getDayCountOfaMonth 的实现我没看出来锅在哪里。

movePrevMonth ,本来就是一个简单的功能,没啥太复杂的思考。

dealloc 的问题,你可能不知道,在早期 SDK 的时候, bug 比较多,我们要实验各种方法避免内存泄漏,有些写法比较诡异,但是在某个版本下,反而效果是好的。到了今天 SDK 也还是会出现一些问题。

这个东西开源完了以后的大概 2-3 年,很火,每天都有邮件来咨询各种问题,最早版本,甚至没有 demo 代码和事例。后来问的人多了,就加上了(在项目说明里面,不过 google code 已经把这些部分都吃掉了,维护过 google code 项目的人应该知道)。

后来,系统提供了一个什么方法我记不得了,而且开源的日历比较多,而且都比这个好看,这个慢慢就无人问津了吧。

最搞笑的是,曾经有个人想把这个东西汉化(操,不知道用什么词好,本地化?)成老挝语,还是柬埔寨语来着,但是代码不是完全看得懂,还写了长篇大论来问我。

不过,我好像从来没有说过这个日历有多牛,这个日历甚至都没有任何的图片资源,一切都是用字符和画线的方式画的。我的所有描述大概应该都是,在最早的时候, iOS 程序员连日历控件都没有,我需要用的时候怎么办呢?那就自己写一个吧。
pasturn
2016-11-27 20:26:15 +08:00
@tinyfool 该用国际化这个词
tinyfool
2016-11-27 20:28:46 +08:00
@pasturn 只加了某一国而已,而且当时也没有国际化的基础,代码都是写死的,他也想直接换,但是不会
FrankFang128
2016-11-27 20:31:50 +08:00
你这样发帖好么……
谁不知道 Code Review 的体验:

EagleB
2016-11-27 20:46:23 +08:00
@tinyfool getDayCountOfaMonth :我认为在查表的方式好一点;
getDayCountOfaMonth : if/else 花括号,不是啥问题,个人喜好吧
EagleB
2016-11-27 20:53:17 +08:00
@FrankFang128 没事想跟前辈学下,就随便看看。
tinyfool
2016-11-27 20:57:27 +08:00
@EagleB

我觉得你看问题太浮于表面了,这个代码不是不能挑问题,问题很多。

问题是,去挑 1 个 500 行,在 iOS 包括苹果官方,大多数编码规则还在形成期的代码的风格问题,唉。

在那个时间阶段,比较像现在 Swift ,每次升级 iOS SDK ,里面项目模版的写法都会变的一塌糊涂,连苹果的风格都没稳定下来。

关注些更有意义的事情,和更有意义的人吧。

如果你能看到,有道词典 iOS 版第一版的代码,估计你也会觉得很烂。

没错,确实不怎么样,可惜我都找不到了,否则说不定我也可以开源出来(有道同意的话)。不过它的意义在于,让有道至少早了几个月到半年,发版本。对有道的开发者也是一个对 iOS 开发祛魅的过程,原来这么简单就行,这么烂的代码也可以上线,而且下载量这么凶猛,哈哈。
tinyfool
2016-11-27 21:03:50 +08:00
我一直懒得开源,我们实现的 iBookAuthor 解析器和 Cocoa touch Android 版,不过回头等我懒癌结束了,欢迎你们去看你,不过请不要揪着代码风格。看看内容,看看具体实现,看看架构,那两个东西蛮好玩的。

前者还好。后者光把环境搭起来,编译好全部的依赖可能就需要一个小时。

要是真有天我们开了,欢迎去研究研究。


另外,我最近扒了一个 Google 的库,改造成了 Cocoa 的接口,拖延症不加剧的话,也许 1-2 个月会开源,到时候有兴趣可以看看。
EagleB
2016-11-27 21:08:59 +08:00
@tinyfool 嗯,我没有别的意思,只想学习一下。 08 年 10 月, iOS 才发布一年多,苹果风格不稳定,这个问题没考虑到。
tinyfool
2016-11-27 21:14:03 +08:00
July 11, 2008 iPhone OS 2.0 Final 发布,同时才有的 App Store 。
Allianzcortex
2016-11-27 21:19:12 +08:00
@missdeer ?(能被 4 整除且不能被 100 整除)或(能被 400 整除)

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

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

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

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

© 2021 V2EX