iOS开发:代码通用性以及其规范 第一篇(附带,自定义UITextView\进度条\双表显示\瀑布流 代码设计思路)
在iOS团队开发中,我见过一些人的代码,也修改过他们的代码。有的人的代码写的非常之规范、通用,几乎不用交流,就可以知道如何修改以及在它基础上扩展延生。有的人的代码写的很垃圾,一眼看过去,简直会怀疑自己和他是用两种语言在开发,代码可复用性极差,往往一个已写好的功能遇到要扩展(或者让我自己写,在稍微改动的情况下就可以移动其他地方使用)的情况下,需要把他代码全部清掉,自己重新写一个类或者方法出来,反正,改起来,简直就是不能令人愉快的玩耍了。
如果,进入了一家代码不规范的公司,个人建议早走为妙。不然要么以后你坚持自己的风格开发(但是,总要合并吧?总要去处理与自己模块相应的逻辑吧),要么代码风格变成和他们一样,要么将他们代码风格变成和自己的一样。
废话不多说,有闲工夫写这,主要是代码写的太快,没控制好,把一周的任务两天写完了,剩下的时间只好看书、分析、总结以前的东西了,还可以理顺自己设计代码的思路。
个人有个人的代码风格,但规范确是通用的。这次写的博客,主要是分享自己关于代码规范、通用性上得一些心得。
规范这一块,主要分两点,命名规范,其次就是看封装规不规范。
命名规范,我觉得官方的命名很有意思。很多程序员都吐槽OC很乱很糟糕,swift是那么的美好。对swift不作评价,但是说OC很糟糕的人,只怕是没有真正写过多少OC代码吧?没有真正体会过苹果官方代码吧?
事实上,只要参照官方的命名,会发现代码要多优美就有多优美,读起来朗朗上口,写起来非常通顺,当然这是个人感觉。
所以,从命名这样一个角度来说,我觉得只要多看看官方代码命名方式,参照写就好。买一本[Effective Objective-C 2.0] OC开发中的圣书,必看。
至于封装,这个不得不吐槽下,我见过有很多人还把从xib\storyboard里面脱线拉出来的控件全部放在.h文件里面?真心怀疑,到底有没有认真学习过面向对象的思想!除了一些特殊的控件,其他的大部分控件,都是不应该让别的开发者在引用我写的这个类的时候可以肆意改变其中我不想让他改的东西的。
甚至,很多时候,他只能单一的readonly 或者 只允许他更改数据,而不允许他持有控件,但无论如何,从xib\storyboard里面脱线拉出来的控件全部放在.h文件里面,这样做法是错误的(正确的写法,在后面会以代码的形式展示)。
代码的通用性:
这一块,必须要重点提下UITableView,在刚接触UITableView以及MVC模式的时候,我在想,为什么我自己所写的view会依赖于model呢?往往一个view对应一种类型的model,而UITableView却不管放入什么数据(model),都可以正确展示??后来,通过一系列的学习,这个问题也得以解决。
代码的通用性,打算将自己在思考过程中写的几个例子好好分析下,让以后的设计有迹可循。
第一个是,带占位文字的UITextView
第二个是,进度条
第三个是,双表(两个UITableView)
第四个是,自定义的瀑布流
先从UITextView说起,我最开始编写的,通用性较强的控件,就应该是它了,代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #import <UIKit/UIKit.h> 2 3 @interface ZYTextView : UITextView 4 @property (nonatomic, copy) NSString *placeText; 5 @property (nonatomic, strong) UIColor *placeTextColor; 6 @end
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #import "ZYTextView.h" 2 3 @interface ZYTextView () 4 @property (nonatomic, weak) UILabel *placeLabel; 5 @end 6 7 @implementation ZYTextView 8 9 - (instancetype)initWithFrame:(CGRect)frame 10 { 11 if (self = [super initWithFrame:frame]) { 12 13 [self commitInit]; 14 15 } 16 return self; 17 } 18 19 - (id)initWithCoder:(NSCoder *)aDecoder 20 { 21 if (self = [super initWithCoder:aDecoder]) { 22 [self commitInit]; 23 } 24 return self; 25 } 26 27 - (void)commitInit 28 { 29 UILabel *placeLabel = [[UILabel alloc] init]; 30 placeLabel.text = @"请输入..."; 31 placeLabel.numberOfLines = 0; 32 33 placeLabel.backgroundColor = [UIColor clearColor]; 34 placeLabel.textColor = [UIColor lightGrayColor]; 35 placeLabel.font = [UIFont systemFontOfSize:14]; 36 37 self.font = placeLabel.font; 38 [self addSubview:placeLabel]; 39 self.placeLabel = placeLabel; 40 41 // 当用户通过键盘修改了self的文字,self就会自动发出一个UITextViewTextDidChangeNotification通知 42 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidChange) name:UITextViewTextDidChangeNotification object:self]; 43 } 44 45 - (void)setText:(NSString *)text 46 { 47 [super setText:text]; 48 49 [self textDidChange]; //当TextView文字用代码改变时,需要调用,因为通知、代理只能监听键盘、鼠标的事件 50 } 51 52 - (void )setAttributedText:(NSAttributedString *)attributedText 53 { 54 [super setAttributedText:attributedText]; 55 56 [self textDidChange]; 57 } 58 59 - (void)setFont:(UIFont *)font 60 { 61 [super setFont:font]; 62 63 self.placeLabel.font = font; 64 65 [self setNeedsLayout]; //当TextView字体改变时,palceLabel应该对应改变,改变之后,需要调用layoutSubviews重新计算文字尺寸等 66 } 67 68 - (void)setPlaceText:(NSString *)placeText 69 { 70 _placeText = [placeText copy]; 71 72 self.placeLabel.text = _placeText; 73 74 [self setNeedsLayout]; //占位文字发生改变时,应该重新计算占位文字尺寸 75 } 76 77 - (void)setPlaceTextColor:(UIColor *)placeTextColor 78 { 79 _placeTextColor = placeTextColor; 80 81 self.placeLabel.textColor = placeTextColor; 82 } 83 84 - (void)layoutSubviews 85 { 86 [super layoutSubviews]; 87 88 89 CGFloat placeLabelX = 0; 90 CGFloat placeLabelY = 8; 91 CGFloat placeLabelW = self.frame.size.width - 2 * placeLabelX; 92 93 CGSize tempSize = CGSizeMake(placeLabelW, MAXFLOAT); 94 CGSize placeSize = [self.placeLabel.text sizeWithFont:self.placeLabel.font constrainedToSize:tempSize]; 95 CGFloat placeLabelH = placeSize.height; 96 self.placeLabel.frame = CGRectMake(placeLabelX, placeLabelY, placeLabelW, placeLabelH); 97 } 98 99 /** 100 * 监听textView文本框情况 101 */ 102 - (void)textDidChange 103 { 104 self.placeLabel.hidden = self.hasText; 105 } 106 107 - (void)dealloc 108 { 109 [[NSNotificationCenter defaultCenter] removeObserver:self]; 110 } 111 @end
要自定义一个带占位文字的UITexiView是很简单的,就是在TextView里面加载一个UILabel,然后监听键盘的输入,随之判断UILabel是否隐藏。但是要写成通用的TextView,思考的东西就比较多了。
首先,占位文字是应该可以随时让外界改变的,毕竟不可能每个项目的占位文字都是相同的。如果是不规范的写法,可能会将
@property (nonatomic, weak) UILabel *placeLabel;
放在.h文件里面。但是仔细思考,在这样一个TextView里面,我所允许外界修改的只是placeLabel的text属性和textColor属性,其他的,比如说placeLabel显示在哪个位置,以怎么样的形式显示,都应该是由内部掌握,外界不该可以修改,所以必须放在.m文件里面。
然后就是,一般在开发中,很多时候我们都会通过代码(而非键盘输入)给TextView一段字符串,这样的情况下,占位文字是应该消失的,等等其他细节(代码里面已标明)。
都考虑到了之后,还要思考,如果同事用我自定义的这个TextView,会不会有什么不方便的?如果有,请补全......总之,自定义一个View,就是让自己和别人用起来感觉特别方便,这就对了。