重构的第一步就是读代码,从中发现其中的坏味道。在最近的一个重构项目中就发现如下的一些不合理点并在阅读过程中考虑了初步的解决方案。
1 控件创建和配置代码
- (void)loadView
{
[super loadView];
CGRect rect = CGRectMake(1, 1, 318, 34);
_urlField = [[UITextField alloc] initWithFrame:rect];
_urlField.borderStyle = UITextBorderStyleBezel;
_urlField.textColor = [UIColor blackColor];
_urlField.delegate = self;
_urlField.text = FIELD_TEXT;
_urlField.backgroundColor = [UIColor whiteColor];
//_urlField.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_urlField.returnKeyType = UIReturnKeyGo;
_urlField.keyboardType = UIKeyboardTypeURL;
_urlField.autocapitalizationType = UITextAutocapitalizationTypeNone;
_urlField.autocorrectionType = UITextAutocorrectionTypeNo;
_urlField.clearButtonMode = UITextFieldViewModeAlways;
[self.view addSubview:_urlField];
}
建议:IB、配置文件
2 死代码
/*
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
// Custom initialization
}
return self;
}
*/
建议:要么删掉,要么不用模板直接手动编写
3 不可能复用的UITableCell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier;
CellIdentifier = [NSString stringWithFormat:@"Cell_%d_%d", indexPath.section, indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
??
}
建议:这种复用等于没有复用
4 不利用模型的“口算”数
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 6;
}
建议:有个dataSource的model,可以直接通过[model count]获取,而自己写意味着实际是一份的数据硬是做成两份,需要解决同步问题。口算解决不了问题。
5 拼写或者语法错误
- (void)showStatue; // showStatus
- (BOOL)isAllowWifi; // isWifiAllowed
建议:不确定的时候多查查字典,并且经常阅读自己的代码
6 多余空行
- (void)loadView
{
[super loadView];
self.tableView.delegate = self;
self.tableView.dataSource = self;
UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithCustomView:p_w_picpathBt];
self.navigationItem.leftBarButtonItem = item;
[item release];
[p_w_picpathBt release];
}
建议:删除最后一行的空行
7 简单罗列判断
- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section
{
int rows = 0;
switch (section) {
case 0:
rows = 1;
break;
case 1:
rows = 2;
break;
case 2:
rows = 3;
break;
case 3:
rows = 1;
break;
default:
break;
}
return rows;
}
建议:建立一个模型,代码比配置文件贵的多
8 奇怪的命名
@interface PasswordSettingView : UITableViewController <UITableViewDelegate, UITableViewDataSource>
建议:UITableViewController继承的应该是Controller,不是View
9 类中定义的静态函数
static void MsgBox(NSString *info)
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:info
message:nil
delegate:nil
cancelButtonTitle:_(@"OK")
otherButtonTitles:nil];
[alertView show];
[alertView release];
}
建议:要不放在公用文件中,要不作为类的一个私有成员函数,总之不要夹杂在类实现中。
10 无所事事函数
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
}
建议:什么都不干的函数。白领饷了
11 多此一举函数
- (void)loadView
{
[super loadView];
}
建议:写了等于没写。所以不要写。
12 正话反说的判断
- (BOOL)checkItem:(Item *)item
{
if (!item || !item.teleplayName || !item.introduction || !item.collectName
|| !item.actor || !item.url || !item.extName)
{
return NO;
}
return YES;
}
建议:玩过正话反说的游戏吗,是不是很累啊?这是一个检查item的函数,对着代码说就是“要是item不存在或者其中的一个属性没有值,就检查不通过,否则就通过”。是不是有点绕啊,自然的描述应该是:“主要item存在并且各个属性都有值就检查通过,否则不通过”。据此表述参考版本如下:
- (BOOL)checkItem:(Item *)item
{
if (item && item.teleplayName && item.introduction && item.collectName
&& item.actor && item.url && item.extName)
{
return YES;
}
return NO;
}
13 徒劳的间接
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (0 == indexPath.row)
{
…….
}
[self performSelector:@selector(deselect)];
}
- (void)deselect
{
[m_tableView deselectRowAtIndexPath:[m_tableView indexPathForSelectedRow] animated:YES];
}
建议:任何软件的问题都可以通过合理的间接解决。不过本例中selector只是引入间接但没有独特地解决问题,因此没有意义
14 奢侈的分配
@interface InfoSync : NSObject
{
Downloader *baseKeywords;
Downloader *incrementKeywords;
}
建议:能复用就没有必要各分配一个。
15 被扒开的UIApplication
@interface GameCenterApp : UIApplication <UIApplicationDelegate>
建议:定制UIApplicationDelegate也能实现的情况下,尽量定制UIApplicationDelegate,而不是定制UIApplication本身。UIApplication已经将预见到地定制点通过UIApplicationDelegate抛给了应用开发者,又何必去扒开它呢?
16 不合理单例
@interface GameCenterCmd : NSObject
{
}
+ (GameCenterCmd *)sharedInstance;
建议:一般情况下命令不可能是单例的。即使实现再精妙也不合理。