iOS代码规范和优化建议

公司须要写一个代码规范,本人第一次写,完成后记录在blogweb

1、命名规范数据库

一、类定义编程

例: ThisIsAClass,

采用苹果推荐的方式,首字母大写,多个有实际意义的英文单词组成,每一个单词的首字母大写。json

在此基础上类名须要体现出这个类的类型swift

试图控制器:ThisIsAViewController
试图:ThisIsAView
按钮:ThisIsAButton
等等数组

我的不建议使用缩写,由于代码补全很是完善,单词再长也不会影响方便性,但缩写影响可读性
可讨论决定是否可以使用相似 ThisIsAVC,ThisABtn,之类的缩写方式缓存

二、属性安全

例:thisIsAObjectruby

首字母小写,多个有实际意义的英文单词组成,每一个单词的首字母大写。bash

在此基础上,须要提示这个变量的类型或者用途。

例如:

UITextField * userNameTextField;

UIButton * leftTopButton,doSomeActionButton;

等等

缩写问题同上,可讨论。

三、成员变量

_menberObject

在属性的基础上,须要如下划线开头。

其余规则和属性同样。

四、局部变量

参照属性

五、函数命名

首字母小写,多个有意义的单词组成,:后面首字母小写

例:

- (void)loginButtonDidPressed; - (void)loginWithUserName:(NSString) userName password:(NSString *) password;

等等

六、函数形参

参照属性

如有可能与属性命名相同或者冲突,建议加上in,a等前缀

例:

- (void) someMethod:(id) inValue anotherObject:(id) aObject
{
    _vlaue = inVlaue;
    self.object = aObject;
}

7 、前缀

因为oc没有命名空间的概念,全部苹果建议使用前缀来防止第三方库、子工程之间命名冲突。

目前咱们的工程中有的没有前缀,有前缀的又不统一,须要讨论是否统一。

2、代码组织

一、概述

目前咱们的工程都采用MVC构架

因此页面代码都至少要包含,View(特别简单的可能省略),VewController(UIVewController子类),ModelManager(这么命名是区分于瘦model,也就是entity)

三者之间最好经过接口互相访问,隐藏实现细节。

好比,VC不须要知道view有哪些label,textfileld,只须要view提供加载数据的方法就能够,实现松耦合。这样若是只是页面排版变了,只要修改接口实现就能够,不用修改其余部分。这也是swift发布后,苹果提出的面相接口(协议)编程的思想。

规则提出的目的,都是指导咱们对各模块之间职能划分,使各自功能单一,松散耦合,任一一方修改,尽量的不影响其余模块。

二、页面
UIView:只作显示逻辑不作业务逻辑,它应该是纯被动的接受VC提供的数据,进行展现。
对用户操做进行收集,提示VC事件发生。

下面提供一些开发场景的处理建议:

case 1

若是view包含一个imageview,性别变量sex,值为male,显示图a,sex为female,显示图b,这种逻辑应该在VC中实现,而不该该把sex传给给View去保存。

//VC中
- (void) someMethod
{
    if (self.sex == male) //假设male为枚举
    {
        [view loadImage:imageA];
    }
    else
    {
        [view loadImage:imageB];
    }
}

//view中

- (void)loadImage:(UIImage *)inImage
{
    self.imageView.image = inImage;
}

case 2

不要在init方法中,去取自身的frame,并以此对子view设置frame,而应该在layoutSubviews中设置
由于不少时候,init方法中,view自己的frame并非最后显示的frame

- (void)layoutSubviews
 {
    // 必定要调用super的方法
    [super layoutSubviews];

    //子view的frame设置
    …
}

case 3

只是堆砌子View的状况通常不太须要自定义view。
自定义view,其实更应该发生在须要重载drawRect方法,或者事情响应touchesBegan/touchesEnded等方法时。而大部分状况其实不须要重载这些方法。只须要addSubvew。
这种状况其实更应该考虑是建一个子视图控制器,毕竟管理一个视图层级(view hierarchy)是VC的事情。

三、视图控制器

试图控制器负责:从而且只从modelManager获取数据,展现到View上。而且接受modelManager数据变化发生时通知,提供回调方法。

开发场景:
case 1

loadView:通常不建议重载,实在要用根据文档所诉,只应该建立视图层级(view hierarchy)也就是只应该作alloc和addSubview。而且若是重载它了,不要调用super,额外的赋值需在viewDidload以后再作。
注意:若是使用了xib或者storyboad就不要重载这个函数。而应该使用awakeFromNib。

case 2
viewDidload:做为入口,但愿它能比较简洁直观,因此建议它内部只出现toDoList型的函数,具体的实现到各个函数中实现。
例如:

- (void) viewDidLoad
{
    [super viewDidLoad];

    [self setupViews];
    [self registerNotifications];
    [self setupModelManager];
    [self doOtherThing];
}

建议在viewDidload中使用自动布局来管理View及子view的frame

case 3

viewwill/DidlayoutSubviews:这对函数在 view调用layoutSubviews先后调用。若是你没用使用自动布局,应该在这两个函数中对view进行位置的设置。

case 4

关于展现用的数据,除非必要,不建议用额外的属性/成员变量保存。而直接经过modelManager的函数得到。以便由modelManager控制数据保存的位置是内存变量,仍是持久化方式。
实在须要在内部函数间传递,也尽可能根据最小知道原则,保存索引,状态值之类的数据。

四、modelManager

modelmananger负责从一个或多个数据源,采集数据业务操做后提供给VC,数据来源多是数据库,内存缓存,网络等中的一个或多个。

开发场景

case 1

对VC隐藏数据源的原始数据结构。
也就是说尽可能不要把数据源原始数据直接交给VC,而应该与VC约定好相互之间须要传递的最小单元(实体/瘦model),把从一个或多个数据源获取的原始数据,转化成该最小单元。提供给VC

case 2

与VC交互的协议接口定义,应足够独立,一个事件/一次数据请求,一般不该该须要调用到其余接口(这里不是说不能调其余内部函数,而是对VC 开放的其余接口)

case 3

接口实现优先进行内存操做,内存没有的数据再操做数据库,尚未再进行网络操做。实现多级缓存及时反馈。

case 4

页面之间的数据变动响应,应该在modelManager之间通知和响应
具体来讲:
vc1某操做,致使vc1的modelManager有数据变动,这个变动影响到v2,那么不该该由v2去接受这个变动通知,而应该由vc2的modelManager接受并修改自身的数据,经过本身的数据变动接口通知vc2。
也就是说一个VC只接受一个modelManager的数据更新通知。

case 5

尽管上面的建议一个VC只对应一个modelManager。但有些场景下,多个VC能够共享一个modelManager。
例:
设置功能下有多个子设置项,这些设置项是不一样子页面操做去设置的而且很简单,当咱们把设置项的数据做为一个总体去考虑的时候,这些子设置项操做的其实应该是同一个数据对象。此时应该支持这些页面传递modelManager对象来共享它。

五、其余衍生组件

在MVC的框架下,可根据功能单一原则,拆分出多个功能组件,供三大框架模块使用,好比数据库模块,网络模块,加密模块,播放器模块等等。

3、代码优化建议

case 1

任何状况下老是使用setValue:forKey代替setObject:forKey
由于前者在value非nil状况下等于后者。
在value为nil删除key所对应的键值。因为赋值时通常当前并不会存在key的键值,即便是覆盖某对键值,在值为空的状况下,删除了它也是合理的。
因此前者效果彻底等效于检测value非空后调用后者。
后者object为nil则直接crash。
因此使用setValue:forKey更安全。

case 2

隐藏没必要要的接口和属性。
那些只在内部使用的属性和函数,应定义在类扩展之中,把少数愿意暴露出去的函数和属性定义在头文件中。

case 3

尽可能不要使用成员变量,用类扩展中的属性代替它。而后老是使用self.去访问它。
这样有更清晰的内存管理。
而且,当有一天你忽然须要在赋值或者取值的时候作一些事情的时候,你就只须要在set/get中操做。而不用整个类里面处处修改了。

case 4

尽可能不要阻塞主线程,尽可能把非UI操做放到其余线程执行,完成后回到主线程通知UI刷新。

case 5

NSSet/NSArray,他们的区别是,NSSet是无序的,当一个数据集合不关注排序时,使用NSSet,查找元素是否存在和移除效率是高于NSArray的。
例:
维护一个操做中的数据集合,操做开始后加到集合中,操做完成后移除出集合,这种状况下应当使用NSSet

case 6

不管何时经过索引访问数组都应该进行越界判断。或者try catch

case 7

懒加载,对不经常使用的View,不要在页面打开时就建立,采用懒加载的方式去实现。以减小页面启动时间。

case 8

预加载,对于加载速度比较慢,又须要进入页面就直接显示的数据,考虑在适当的时间提早加载好,驻留在内存中。空间换时间。

case 9

tableView的使用除了注意cell正确重用之外,还需注意,数据源的count变化,特别是变小是要及时reloadData。若是使用insertRow/removerow操做,必定要保证数据源数量等于变化前数量加/减变化数量,不然就会crash

case 10

实体中只能进行简单的数据操做,例如json转字典,数值转字符,取整之类的。不能进行业务操做,如存取数据库,网络操做等。

case 11

使用大量临时变量时,可用@autoreleasepool来包含起来及时释放。