pod私有化,在组件中包含*.xcassets资源时需要做什么

在百度上搜索了上百条信息,我是真的要吐槽一下,真的搜不到呀,下面的文章记录一下,以防以后忘记了!

这里只是针对这个问题做一个解释,如有问题,请留下宝贵意见:

1、需要在*.podspec文件中加入如下代码

1
2
3
4

s.resource_bundle = {
'AAA' => ['目录/Assets/*.xcassets'] #AAA为生成boudle的名称,随便起,记下,下面要用
}

2、在需要引入*.xcassets中的图片资源时,调用如下方法:

1
2
3
4
5
6
7
8
9
10
11
12

UIImage *img = [self getImageWithBoudleName:@"AAA" imgName:@"图片名称"];

- (UIImage *)getImageWithBoudleName:(NSString *)boudleName imgName:(NSString *)imgName {
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSURL *url = [bundle URLForResource:boudleName withExtension:@"bundle"];
NSBundle *targetBundle = [NSBundle bundleWithURL:url];
UIImage *image = [UIImage imageNamed:imgName
inBundle:targetBundle
compatibleWithTraitCollection:nil];
return image;
}

特别鸣谢

iPad全部机型
ipad 1-6 (9.7)
ipad mini 1-4(7.9)
ipad Air 1-2 (9.7)
ipad Pro 1-3 (12.9)
ipad Pro (9.7)
ipad Pro (10.5)
ipad Pro (11)
需要适配的机型
ipad 5-6 (9.7)
ipad mini 4(7.9)
ipad Air 2 (9.7)
ipad Pro 1-3 (12.9)
ipad Pro (9.7)
ipad Pro (10.5)
ipad Pro (11)
机型识别:https://support.apple.com/zh-cn/HT201471#ipadair

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
iOS-Component/
|- readme.md (说明)
|- 工程/
| |- Config/ (基础配置文件)
| |- Modules/ (功能模块)
| | |- Home/
| | | |- Connector/ (接入点)
| | | |- Model/ (内部数据模型)
| | | |- Service/ (该组件的网络接口请求以及网络回调回来的数据转Model工作)
| | | |- UI/ (页面存放位置)
| | | |- / ()
| | |- Mine/
| | |- .../
| | |- Login/
| |- Manager/ (管理模块)
| |- CommonParty/ (基础内部通用文件,如添加或修改,需经过论证)
| | |-
| | |-
| | |-
| |- ThirdParty/ (基础外来三方文件,如添加或修改,需经过论证)
| | |-
| | |-
| | |-
| |- Define/ (全局宏定义)
| |- Base/ (基础文件,如修改,需经过论证)
| | |- Frame/ (布局)
| | | |- UIViewAdditions/
| | |- DataBase/ (数据库)
| | |- HttpReq/ (网络请求)
| | |- Root/ (基类)
| | |- PostModel/ (基础Model)
| | |- Utils/ (工具类)
| | |-
| | |-
| | |-
| |- Assets.xcassets/ (图片)
| |- Resource/ (资源文件夹)
| |- Supporting Files
|
|
| |-Pod/ (Pod导入文件列表)
| | |- AFNetWroking
| | |- SDWebImage
| | |- FMDB
| | |- Reachability
| | |- MJRefresh
| | |- MJExtension
| | |- MBProgressHUD
| | |- NullSafe
| | |- IQKeyboardManager
| | |- FSCalendar
| | |- pop
| | |-
| | |-
| | |-
|
|
|
|
|
|
|

面试心得

  • 什么是arc?(arc是为了解决什么问题诞生的?)
    现在有不少程序员是直接从arc上手的,从没接触过mrc,对arc的理解仅仅停留在apple帮助管理内存的层面。这个问题真正想了解的是对内存管理的理解,retain release虽然不用写了,但arc下还是会有内存泄漏野指针crash的bug存在。如果能从retain count这种内存管理策略的角度去阐述arc诞生的意义就算答对了。如果还能扯下其他类型的策略,比如java里的mark and sweep,那就加分点赞。
    请解释以下keywords的区别: assign vs weak, block vs weak
    这道题属于基础语法题,可以网上搜到答案。不过真有不少同学不知道weak在对象释放后会置为nil。__block关键字的理解稍微难点,因为在arc和mrc下含义(对retain count的影响)完全不同。理解了这几个关键字就能应付使用block时引入retain cycle的风险了。这题还在内存管理的范畴之内。
  • 使用atomic一定是线程安全的吗?
    看这题的问法不用想答案肯定是NO。有些人说不出所以然,有些人知道通过property的方式使用才能保证安全,还有人知道这个用来做多线程安全会有性能损耗,更有出色的候选人能谈atomic,synchronized,NSLock,pthread mutex,OSSpinLock的差别。好奇宝宝点我。
    描述一个你遇到过的retain cycle例子。(别撒谎,你肯定遇到过)
    说没遇到过的我很难相信你有过成熟项目的经历。这题答不出了会扣很多很多分。用过block,写过delegate的肯定都踩过坑。
  • +(void)load; +(void)initialize; 有什么用处?
    这题属于runtime范畴,我遇到过能说出对runtime的理解却不知道这两个方法的候选人。所以答不出来也没关系,这属于细节知识点,是加分项,能答出两个message各在什么阶段接收就可以了。
    为什么其他语言里叫函数调用, objective c里则是给对象发消息(或者谈下对runtime的理解)
    这题考查的是objective c这门语言的dynamic特性,需要对比c++这类传统静态方法调用才能理解。最好能说出一个对象收到message之后的完整的流程是如何的。对runtime有完整理解的候选人还能说出oc的对象模型。
  • 什么是method swizzling?
    说了解runtime但没听过method swizzling是骗人的。这题很容易搜到答案。定位一些疑难杂症bug,hack老项目实现,阅读第三方源码都有机会接触到这个概念。
  • UIView和CALayer是什么关系 7
    能答出UIView是CALayer的delegate就及格了,能说出UIView主要处理事件,CALayer负责绘制就更好,再聊下二者在使用过程中对动画流畅性影响的注意点就superb。UI流畅性是个大话题,推荐看下这两篇文章。中餐,西餐。
  • 如何高性能的给UIImageView加个圆角?(不准说layer.cornerRadius!)5
    这题讨论的最多,还有说美工切图就搞定的。答主在项目里做过圆角头像的处理,里面的坑还真不少。cornerRadius会导致offscreen drawing有性能问题,美工切图无法适用有背景图的场景,即使加上shouldRasterize也有cache实效问题。正确的做法是切换到工作线程利用CoreGraphic API生成一个offscreen UIImage,再切换到main thread赋值给UIImageView。这里还涉及到UIImageView复用,圆角头像cache缓存(不能每次都去绘制),新旧头像替换等等逻辑。还有其他的实现方式,但思路离不开工作线程与主线程切换。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
- (UIImage*)circleImage {
UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0);
CGContextRefctx = UIGraphicsGetCurrentContext();
CGRectrect = CGRectMake(0, 0, self.size.width,self.size.height);
CGContextAddEllipseInRect(ctx, rect);
CGContextClip(ctx);
[selfdrawInRect:rect];
UIImage*image =UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
returnimage;
}


UIImageView*imageView = [[UIImageViewalloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
imageView.center = CGPointMake(200,300);
UIImage*anotherImage = [UIImageimageNamed:@"image"];
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 1.0); [[UIBezierPathbezierPathWithRoundedRect:imageView.bounds cornerRadius:50] addClip];
[anotherImage drawInRect:imageView.bounds];
imageView.image =UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self.view addSubview:imageView];
  • UITableView优化方法
    cell重用,异步执行耗时操作这种就不用提了,这都是大家能想到的,我们可以说一点其他的。
    1:减少视图层次;
    2:正确使用api,比如设置rowHeight而不去取dataSource;
    3:减少离屏渲染;
    圆角图片
    阴影

    4:设置视图不透明减少渲染代价,如果有透明度则会根据多个视图才知道一个像素点显示什么颜色;
    5:RunLoop空闲计算cell高度并缓存;
    6:利用RunLoop的mode在滚动时不执行耗时操作。
  • 如何用GCD同步若干个异步调用?(如根据若干个url异步加载多张图片,然后在都下载完成后合成一张整图)
  • dispatch_barrier_async(栅栏函数)的作用是什么?
    1.在它前面的任务执行结束后它才执行,它后面的任务要等它执行完成后才会开始执行。
    2.避免数据竞争
  • 以下代码运行结果如何?
1
2
3
4
5
6
7
8
- (void)viewDidLoad {
[superviewDidLoad];
NSLog(@"1");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"2");
});
NSLog(@"3");
}
  • 使用drawRect有什么影响?(这个可深可浅,你至少得用过。。)
    不少同学都用过drawRect或者看别人用过,但不知道这个api存在的含义。这不仅仅是另一种做UI的方式。drawRect会利用CPU生成offscreen bitmap,从而减轻GPU的绘制压力,用这种方式最UI可以将动画流畅性优化到极致,但缺点是绘制api复杂,offscreen cache增加内存开销。UI动画流畅性的优化主要平衡CPU和GPU的工作压力。推荐一篇文章:西餐
    ASIHttpRequest或者SDWebImage里面给UIImageView加载图片的逻辑是什么样的?(把UIImageView放到UITableViewCell里面问更赞)
    很多同学没有读源码的习惯,别人的轮子拿来只是用用却不知道真正的营养都在源代码里面。这两个经典的framework代码并不复杂,很值得一读。能对一个UIImageView怎么通过url展示一张图片有完整的理解。涉及到的知识点也非常多,UITableViewCell的复用,memory cache, disk cache, 多线程切换,甚至http协议本身都需要有一定的涉及。
    麻烦你设计个简单的图片内存缓存器(移除策略是一定要说的)
    内存缓存是个通用话题,每个平台都会涉及到。cache算法会影响到整个app的表现。候选人最好能谈下自己都了解哪些cache策略及各自的特点。常见的有FIFO,LRU,LRU-2,2Q等等。由于NSCache的缓存策略不透明,一些app开发者会选择自己做一套cache机制,其实并不难。
  • 讲讲你用Instrument优化动画性能的经历吧(别问我什么是Instrument)
    Apple的instrument为开发者提供了各种template去优化app性能和定位问题。很多公司都在赶feature,并没有充足的时间来做优化,导致不少开发者对instrument不怎么熟悉。但这里面其实涵盖了非常完整的计算机基础理论知识体系,memory,disk,network,thread,cpu,gpu等等,顺藤摸瓜去学习,是一笔巨大的知识财富。动画性能只是其中一个template,重点还是理解上面问题当中CPU GPU如何配合工作的知识。
    loadView是干嘛用的?
    不要就简单的告诉我没用过,至少问下我有什么用。。这里是apple给开发者自己设置custom view的位置。说UI熟悉的一定要知道。
    viewWillLayoutSubView你总是知道的。。
    controller layout触发的时候,开发者有机会去重新layout自己的各个subview。说UI熟悉的一定要知道。
  • GCD里面有哪几种Queue?你自己建立过串行queue吗?背后的线程模型是什么样的??
    两种queue,串行和并行。main queue是串行,global queue是并行。有些开发者为了在工作线程串行的处理任务会自己建立一个serial queue。背后是苹果维护的线程池,各种queue要用线程都是这个池子里取的。GCD大家都用过,但很多关键的概念不少人都理解的模凌两可。串行,并行,同步,异步是GCD的核心概念。
    用过coredata或者sqlite吗?读写是分线程的吗?遇到过死锁没?咋解决的?
    没用过sqlite是说不过去的。用过CoreData的肯定有很多血泪史要说。多谢线程模型你肯定做过比较选择。死锁是啥肯定也是要知道的,没遇到过至少能举个简单的例子来说明。单个线程可以死锁(main thread里dispatch_sync到main queue),多个线程直接也可以死锁(A,B线程互相持有对方需要的资源且互相等待)。
  • http的post和get啥区别?(区别挺多的,麻烦多说点)
    这个可以说很多。不希望听到的答案有
    两个差不多,随便用一个。
    post比get安全(其实两个都不安全)
    能说下两个http格式有什么不同,各自应用的场景就合格了。更多可以阅读下这个答案。

1、如何令自己所写的对象具有拷贝功能?

2、说说你理解weak属性?

3、题目:Swift mutating关键字的使用?

4、UIView和CALayer是什么关系?

5、下面的代码输出什么?

6、@synthesize 和 @dynamic 分别有什么作用?

7、动态绑定

8、Category(类别)、 Extension(扩展)和继承的区别

9、为什么代理要用weak?代理的delegate和dataSource有什么区别?block和代理的区别?

10、id和NSObject*的区别

11、如何令自己所写的对象具有拷贝功能?

12、使用系统的某些block api(如UIView的block版本写动画时),是否也考虑引用循环问题?

13、用@property声明的NSString(或NSArray,NSDictionary)经常使用copy关键字,为什么?如果改用strong关键字,可能造成什么问题?

14、UIView和 CALayer是什么关系?

15、static有什么作用?

底层:

16、main()之前的过程有哪些?

17、KVO基本原理?

18、Swift 下的如何使用 KVC?

19、:Swift有哪些模式匹配?

20、objc在向一个对象发送消息时,发生了什么?

21、静态库的原理是什么?你有没有自己写过静态编译库,遇到了哪些问题?

22、runloop是来做什么的?runloop和线程有什么关系?主线程默认开启了runloop么?子线程呢?

23、不手动指定autoreleasepool的前提下,一个autorealese对象在什么时刻释放?(比如在一个vc的viewDidLoad中创建

24、不手动指定autoreleasepool的前提下,一个autorealese对象在什么时刻释放?(比如在一个vc的viewDidLoad中创建)

25、OC完整的消息转发机制+代码实现【暴击】

26、、以+ scheduledTimerWithTimeInterval…的方式触发的timer,在滑动页面上的列表时,timer会暂定回调,为什么?如何解决?

27、如何手动触发一个value的KVO

28、如何对定位和分析项目中影响性能的地方?以及如何进行性能优化?

29、串行并行,异步同步的区别?

30、线程是什么?进程是什么?二者有什么区别和联系?

31、RunLoop是什么?

32、假设有一个字符串aabcad,请写一段程序,去掉字符串中不相邻的重复字符串,即上述字符串处理之后的输出结果为:aabcd

@autoclosure(自动闭包)

34、iOS app启动如何优化?

35、swift面试题:

36、怎样防止反编译?

37、UITableView性能优化,超实用

线程:

37、 不要阻塞主线程

38、谈谈你对多线程开发的理解?ios中有几种实现多线程的方法?

39、进程和线程的区别?同步异步的区别?并行和并发的区别?

40、ViewController生命周期

41、iOS 中的多线程

42、内存管理的几条原则时什么?按照默认法则.那些关键字生成的对象

需要手动释放?在和property结合的时候怎样有效的避免内存泄露?

谁申请,谁释放

43、dispatch_barrier_async的作用是什么?

44、如何用GCD同步若干个异步调用?(如根据若干个url异步加载多张图片,然后在都下载完成后合成一张整图)

http:

46、http与https的区别?

47、服务器能否知道APNS推送后有没有到达客户端的方法?

app:

48、1.什么方式可以看到上架App的头文件?

2.阅读过哪些框架的源码?能说说它的架构方式吗

49、iOS iAP内购审核可能失败的问题

50、IAP内购中虚拟货币导致审核无法通过的问题?

面试整理
1、TableView卡顿的优化~案例~tableView的重用机制?
2、

1
2
3
3、三方库的解析
4、LRU、LFU,数据持久化储存(Least Frequently Used)(Least recently used,最近最少使用)
5、GCD用的多吗?都怎么用的,```group、notify,berries,semaphore

6、布局方式
7、KVO的实现原理,NSKVONotifying_A
8、性能优化
9、runtime用的多吗
10、

11、擅长的东西
12、js交互
13、移动端目前的打包方式,内部发布的时候怎么进行安装!
14、property的修饰符有哪些来自 简书

15、runloop,mode有timer、source、common和observer
16、bug处理,dsym,
17、移动端线上测试,mqc,最大崩溃率,体验不好,临时处理方式
pod ‘Bugly’腾讯出品,都怎么调试,

18、一个Universal程序还是iPhone、iPad俩个版本 ?
19、老鼠的问题
20、iOS 以scheduledTimerWithTimeInterval的方式触发的timer,在滑动页面上的列表时,timer会暂停,为什么?该如何解决
21、OC中protocol、category继承的区别 extension 来自 cocoachina

用category的好处
(可以添加实例方法,类方法,甚至可以实现协议,添加属性)和不可为(无法添加实例变量)。
22、介绍项目,注册用户最多的一个
23、招合适的人
24、本地推送,远程推送
25、typedefdefine 使用注意 来自 简书
26、UIImage加载图片性能问题 来自 简书
27、你大概知道一个类的名字,现在你定位到这个类!
28、收费视频处理流程
29、AutoreleasePool的释放有如下两种情况 runloop即将结束,drain
30、字典转模型,MJExtension
31、怎么发现离屏渲染 来自 cnblog
32、JSPatch 来自 cnblog

代码规范

目的

为了利于项目维护以及规范开发,促进成员之间Code Review的效率,故提出以下开发规范,如有更好的建议,欢迎提出。
本文档的预期读者包括:iOS开发人员

代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。正确的英文拼写和语法可以让阅读者易于理解,避免歧义。

*注意:即使纯拼音命名方式也要避免采用。但alibab、taobao、youku、hangzhou等国际通用的名称,可视同英文.

小驼峰原则:第一个单词首字母小写,其余都大写。例:nameTextField。

项目命名

  • 项目名都遵循大驼峰命名。例如:AoRiseProject。
  • Bundle Identifier 命名
  • Bundle Identifier:采用反域名命名规范,全部采用小写字母,以域名后缀+公司顶级域名+应用名形式命名,例如:com.hlsk.hedpapp
    类名
  • 类的命名都遵循大驼峰命名。一般是:前缀 + 功能 + 类型。例如:HYC + Login + ViewController
  • 在实际开发中,一般都会给工程中所有的类加上属于本工程的前缀。
  • 常用控件类命名类型对照表(下表中前缀为:HYC,如果用到下表中没有列举出来,请去掉UI首字母,遵循实际规则即可。)
控件名 类型 示例
UIViewController ViewController HYCBaseViewController
UView View HYCBaseView
UITableView TableView HYCOrderTableView
UITableViewCell Cell HYCOrderListCell
UIButton Button HYCSuccessButton
UILabel Label HYCSuccessLabel
UIImageView ImgView HYCGoodsImgView
UITextField TextField HYCNameTextField
UITextView TextView HYCSuggestTextView
  • 其它类相关对照表
功能 类型 示例
工具类 Tool HYCOrderTool
代理类 Delegate HYCOrderListDelegate
管理类 Manager HYCOrderListModel
模型类 Model HYCOrderListModel
Service类 Service HYCOrderService
布局类 Layout HYCHomeLayout
数据库类 DataBase、表名+DBHelper HYCFriendDataBase、HYCUserTableDBHelper

类目
XXX+(范围,例如Extension, Additions 或者功能,例如Frame,Nib,Block)
HYCUIButton+Additions、HYCUIButton+Block

1
2
3
4
5
6
7
UIViewController请按照如下分类
#pragma mark - life cycle
#pragma mark - event response
#pragma mark - UITableViewDelegate && UITableViewDataSource
(代理顺序往下排列)
#pragma mark - getters and setters
#pragma mark - private

注意:所有视图或者对象的创建请尽量使用懒加载,调用的时候全部使用self.textBtn这样的方式。如果是确定的不可变数组、字典,可直接给定数组中的元素。(getters and setters分类中,懒加载可出现_调用对象,其它情况请遵循self.调用原则)

1
2
3
4
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong)UIButton * textBtn;
@end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
    @implementation ViewController

#pragma mark - life cycle
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.textBtn];
}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - private

#pragma mark - event response

#pragma mark - UITableViewDelegate && UITableViewDataSource
//(代理顺序往下排列)

#pragma mark - CTAPIManagerCallBackDelegate

#pragma mark - getters and setters
- (UIButton *)textBtn
{
if (_textBtn == nil) {
_textBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_textBtn.frame = CGRectMake(300, 250, 100, 100);
_textBtn.backgroundColor = [UIColor yellowColor];
_textBtn.titleLabel.text = @"text";
[_textBtn addTarget:self action:@selector(text) forControlEvents:UIControlEventTouchUpInside];
}
return _textBtn;
}
@end

变量和方法
变量和方法的命名都遵循小驼峰命名。例如:textVariableStr, - (void)textAction响应事件。
变量命名对照表(如果用到下表中没有列举出来,请去掉UI、NS遵循实际规则即可。或者一看就知道的通用简写)
方法命名对照表(方法多为动词或动名词)

功能/示例

- (id)initXX
初始化相关方法,使用init为前缀标识,如初始化布局- (id)initView

- (BOOL)isXX
方法返回值为boolean型的请使用is前缀标识

- (UIView *)getXX
返回某个值的方法,使用get为前缀标识

- (void)setXX
设置某个属性值或者相关数据

- (void)updateXX
更新数据

- (void)saveXX
保存数据

- (void)drawXX
绘制相关,使用draw前缀标识

- (void)clearXX
清除数据

- (void)XXXAction
响应事件,使用Action为后缀标识

- (void)loadData
加载数据(一般情况下VC中都会有这个方法)

- (void)loadMoreData
加载更多数据

- (void)setupUI
加载布局(一般情况下VC中都会有这个方法)

方法的命名
当方法参数在三个以及三个以上,换行保持对齐(冒号对齐,冒号前是参数变量,冒号后是参数值).
方法声明:

1
2
3
4
5
+ (instancetype)initWithPersonName:(NSString *)name
withAge:(int)age
withSex:(NSString *)sex
withHeight:(float)height
withWeight:(float)weight;

方法调用:避免使用冒号对齐的方式.

常量
宏:小写k+大驼峰 即为:#define kUserAgeKey @“ageKey”
全局常量:工程前+缀全大写,下划线隔开 即为:extern const NSString MW_USER_AGE_KEY
参数名
参数名以小驼峰命名,尽量参考苹果原生方法风格编写。尽量可读性好,看到方法名就知道这个方法是用来干什么的。参数应该避免用单个字符命名。例:- (void)setDataImageUrl:(NSString *)imageUrl name:(NSString *)nameStr content:(NSString *)contentStr
资源文件命名
全部小写,采用下划线命名法,加前缀区分。所有的资源文件都需要加上工程前缀(小写形式)。
命名模式:可加后缀_small表示小图,_big表示大图,逻辑名称可由多个单词加下划线组成,采用以下规则:

用途_模块名_逻辑名称 用途_模块名_颜色 用途_逻辑名称 用途_颜色

说明 前缀(工程前缀示例MW) 示例
按钮相关 hyc_btn_ hyc_btn_home_normal、hyc_btn_red,hyc_btn_red_big
背景相关 hyc_btn_ hyc_bg_home_header、hyc_bg_main
图标相关 hyc_ic_ hyc_ic_home_location、hyc_bg_input
分割线相关 hyc_div_ hyc_ic_home_location、hyc_bg_input
默认相关 hyc_def_ hyc_ic_home_location、hyc_bg_input

文件夹命名
创建文件夹最好创建实体文件夹,找到工程目录,创建相应文件夹并拖入工程。文件夹命名使用相应模块结构分层的英文,首字母要大写。例:Model,View,Controller,Tool,Other,Service等等。

采用US(美式)英语,不使UK(英式)英语或汉字拼音.

1
2
3
US: UIColor *myColor =[UIColor blueColor];
UK: UIColor *myColour =[UIColor blueColor];
拼音: UIColor *wodeYanSe =[UIColor blueColor];

宏的命名
以两个大写字母作为前缀,后面遵循大驼峰命名法.

1
2
#define KKScreenWidth ([UIScreen mainScreen].bounds.size.width)
#define KKAppVersion @"appVersion"

枚举的命名
遵循Objective-C内部框架定义方式.
Enum中枚举内容的命名需要以该Enum类型名称开头.

1
2
3
4
5
6
7
typedef NS_ENUM(NSInteger, FulowersMoveDestination)
{
FulowersMoveDestinationTop,
FulowersMoveDestinationBottom,
FulowersMoveDestinationLeft,
FulowersMoveDestinationRight,
};

赋值
在”=”号左右两边各间隔一个空格.

1
static const int count = 0;

类方法或对象方法
方法的”+/-”号和左侧小括号间隔一个空格,方法名称与大括号间隔一个空格

1
2
3
- (void)viewDidLoad {

}

版本规范

采用A.B.C 三位数字命名,比如:1.0.2,当有版本更新的时候,依据下面的情况来确定版本号规范。

版本号 说明 示例
A.b.c 属于重大更新内容 1.0.2 -> 2.00
a.B.c 属于小部分更新内容 1.0.2 -> 1.2.2
a.b.C 属于补丁更新内容 1.0.2 -> 1.0.4

第三方库规范

希望Team能用时下较新的技术,对开源库的选取,一般都需要选择比较稳定的版本,作者在维护的项目,要考虑作者对issue的解决,以及开发者的知名度等各方面。选取之后,一定的封装是必要的。
项目使用cocoapods统一管理开源第三库文件,不需要手动导入和手动添加依赖库。如果第三方不支持cocoapods,可手动导入工程。

类注释
为了减少他人阅读你代码的痛苦值,请在关键地方做好注释。

1
2
3
4
5
6
7
//
// MyViewController.m
// text
//
// Created by Jade on 2017/9/12.
// Copyright © 2017年 Jade. All rights reserved.
//

该注释是自动生成的,在xcode中设置即可。Created by 电脑用户名on 创建该文件的时间。Copyright 2017 后面的名字和邮箱是自己填写和设置的。具体可在xcode工程,Project Document中设置。这样便可在每次新建类的时候自动加上该头注释。
方法注释

方法注释,方法外部统一用option + command + /,方法内部统一用//注释。

/**
测试
*/
- (void)text
{
   //测试按钮事件响应
}


注释

注释是为了解释说明,方法或变量等命名规范合理,清楚易懂,可以不添加注释,含有复杂逻辑的代码必须添加注释.注释需要实时更新,跟随代码的变动进行更改或者删除.
1.公开类方法注释
在.h文件中声明类方法,采用文档注释,要写明方法的具体作用,所有参数的含义以及返回的参数值.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
创建person对象的类方法

@param name 姓名
@param age 年龄
@param sex 性别
@param height 身高
@param weight 体重
@return 返回person类对象
*/
+ (instancetype)initWithPersonName:(NSString *)name
withAge:(int)age
withSex:(NSString *)sex
withHeight:(float)height
withWeight:(float)weight;

方法内部逻辑代码注释
复杂逻辑代码在代码上方进行注释,注释方式采用双斜杠+单个空格+具体注释内容

1
2
3
4
5
6
7
8
9
- (void)viewDidLoad
{
[super ViewDidLoad];
// 注释
if(...)
{
...
}
}

for循环
for和左侧小括号间隔一个空格, i和”<=”间隔一个空格, ”<=”和”3”间隔一个空格, ”3”后面紧跟着封号 ,封号和i间隔一个空格.大括号换行,一对大括号上下位置对齐.

1
2
3
4
for (int i = 0; i <= 3; i++)
{
// 语句
}

条件语句
关于大括号,任何需要大括号的都不能省略.
采用

1
2
3
4
if (isLogin)
{
return success;
}

不是

1
2
if (isLogin)
return success;

也不是

1
if (isLogin) return success;

case语句
当一个case语句包含多行代码时,大括号应该加上.如case 2所示.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
switch (condition) 
{
case 1:
// ...
break;
case 2:
{
// ...
// Multi-line example using braces
break;
}
case 3:
// ...
break;
default:
// ...
break;
}

当在switch使用枚举类型时,default是不需要的.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
switch (FulowersMoveDestination) 
{
case FulowersMoveDestinationTop:
// ...
break;
case FulowersMoveDestinationBottom:
// ...
break;
case FulowersMoveDestinationLeft:
// ...
break;
case FulowersMoveDestinationRight:
// ...
break;
}

单例
统一采用shared+类名作为单例类的方法名

1
2
3
4
5
6
7
8
9
10
11
12
13
@implementation LBYNetworkTool
+ (instancetype)sharedBYNetworkTool
{
static LBYNetworkTool *instance;
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[LBYNetworkTool alloc]init];
});
}
return instance;
}
@end

UI整理
搭建UI时,使用setup作为方法名前缀,将相应UI布局放在对应方法中

1
2
3
- (void)setupTableViewUI
- (void)setupNavigationUI
- (void)setupCollectionViewUI

标记
在函数分组和使用#pragma mark - 给重要逻辑代码添加标记,方便阅读

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#pragma mark - Lifecycle
- (instancetype)init
- (void)dealloc
- (void)viewDidLoad
- (void)viewWillAppear:(BOOL)animated
- (void)didReceiveMemoryWarning

#pragma mark - IBActions
- (IBAction)submitData:(id)sender

#pragma mark - Public
- (void)publicMethod

#pragma mark - Private
- (void)privateMethod

#pragma mark - Custom Protocol
- (void)tabbarBottomView:(LBYTabbarBottomView *)tabbarBottomView didSelectIndex:(NSUInteger)index didSelectBtn:(BYBottomButton *)selectBtn

#pragma mark - UITextFieldDelegate
- (void)textViewDidBeginEditing:(UITextView *)textView;
- (void)textViewDidEndEditing:(UITextView *)textView;

#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

#pragma mark - UITableViewDelegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;

#pragma mark - NSObject
- (NSString *)description

模型注释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
每个model中的,包含的每个属性,都必须要写上相对应的注释,用///注释。阅读者一看这个model,就清楚知道model中的每个字段代表的意思,用来做什么事情的。
@interface DeliveryModel : NSObject
///提货劵所在商圈id
@property (nonatomic, assign) long long mallId;
///商圈全称
@property (nonatomic, copy) NSString *mallFullName;
///商圈简称
@property (nonatomic, copy) NSString *mallShortName;
///提货劵号
@property (nonatomic, copy) NSString *credentialsCode;
///总金额
@property (nonatomic, assign) NSInteger totalAmount;
///提货劵所在店铺id
@property (nonatomic, assign) long long storeId;
///货劵所在店铺名称
@property (nonatomic, copy) NSString *storeName;
///提货劵id
@property (nonatomic, strong) NSNumber *credentialsId;
///状态:0:未提货、1:已提货、2:已分享、3:已退款
@property (nonatomic, assign) NSInteger state;
///提货商品(以下为提货商品参数)
@property (nonatomic, strong) NSArray<DeliveryGoodslist *> *goodsList;
///二维码
@property (nonatomic, copy) NSString *qrCode;
///商品总个数
@property (nonatomic, assign) NSInteger goodsCount;
@end

如果不是model的属性,是其它类属性,需要注释,请按照model属性注释方式。

属性和对象的命名
采用修饰+类型的方式命名,BOOL类型添加is前缀,单词遵循小驼峰命名法.声明属性时,小括号中的顺序依次是:nonatomic,readonly,strong.

1
2
3
4
5
@property (nonatomic, assign) BOOL isLogin;
@property (nonatomic, weak) UITextField *loginNameTextField;
@property (nonatomic, copy) NSString *studentClientName;
@property (nonatomic, weak) UILabel *loginTipLabel;
@property (nonatomic, weak) UIButton *loginButton;

编码规范

  • 所有的方法之间空一行。
  • 所有的代码块之间空一行,删除多余的注释。
  • 所有自定义的方法需要给出注释。
  • 尽量使用懒加载,在控制器分类时有提及和要求,其它自定义类按照控制器格式分类,没有的分类不写即可。
  • 代码后的’{‘不需要独占一行,包括方法之后,if,switch等。
  • 必须要统一的要求,属性的定义请按照下图property之后,空一格,括号之后空一格,写上类名,空一格之后跟上*和属性名。

    1
    2
    3
    4
    @property (nonatomic, strong) UITableView *tableView;
    @property (nonatomic, strong) DeliveryModel *delivery;
    @property (nonatomic, strong) DeliveryLookAdapter *lookAdapter;
    @property (nonatomic, strong) DeliveryLookAPIManager *lookManager;
  • 遵循一般代码规范,多模仿苹果API。

  • 删除不用的代码。
  • 如果有方法一直不会用到,请删除(除工具类)。
  • 没有执行任何业务逻辑的方法,请删除或给予注释,删除多余的资源或文件,添加必要的注释。
  • 比较大的代码块需要给出注释。

其它规范

  • 建议项目统一使用Masonry和xib结合的方式布局。不允许出现直接设置frame的情况。如果是纯代码的项目,不允许出现xib和拉约束的情况。不建议使用纯storyboard开发。???
  • 数据提供统一的入口。无论是在 MVP、MVC 还是 MVVM 中,提供一个统一的数据入口,都可以让代码变得更加易于维护。比如可使用一个DataManager,把 http、preference、eventpost、database 都放在DataManger里面进行操作,我们只需要与DataManger打交道
  • 提取方法,去除重复代码。对于必要的工具类抽取也很重要,这在以后的项目中是可以重用的。(如果是想组件化,重复代码不可避免,而且会增加工作量,因为模块之前是独立的,页面层面的雷同不做抽提)
  • 尽可能的使用局部变量
  • 尽量减少对变量的重复计算。
  • 尽量在合适的场合使用单例。使用单例可以减轻加载的负担,缩短加载的时间,提高加载效率。但并不是所有的地方都适用于单例,简单来说单例主要适用于以下三个方面:
  1. 控制资源的使用,通过线程同步来控制资源的并发访问。
  2. 控制实例的产生,以达到节约资源的目的。
  3. 控制数据的共享,在不建立直接关联的条件下,让多个不相关的进程或线程之间实现通信。
    最后不要忘了检测内存泄漏。可使用Instruments分析内存。

文章来源1
文章来源2