一、ViewController代码结构
在函数分组和protocol/delegate实现中使用#pragma mark -
来分类方法,遵循以下结构:
// 生命周期
#pragma mark - Lifecycle
- (instancetype)init {}
- (void)awakeFromNib {}
- (void)loadView {}
- (void)viewDidLoad {}
- (void)viewWillAppear:(BOOL)animated {}
- (void)viewWillLayoutSubviews {}
- (void)viewDidLayoutSubviews {}
- (void)viewDidAppear:(BOOL)animated {}
- (void)viewWillDisappear:(BOOL)animated {}
- (void)viewDidDisappear:(BOOL)animated {}
- (void)dealloc {}
- (void)didReceiveMemoryWarning {}
// 如果是Storyboard/Xib
#pragma mark - IBActions
- (IBAction)sendBtnClicked:(id)sender {}
// 公开方法
#pragma mark - Public
- (void)publicMethod {}
// 私有方法
#pragma mark - Private
- (void)privateMethod {}
// 各种代理和协议方法
#pragma mark - Protocol
#pragma mark - UITextFieldDelegate
#pragma mark - UITableViewDataSource
#pragma mark - UITableViewDelegate
// 懒加载的Getter
#pragma mark - Getter && Setter
// Copy协议和description较少
#pragma mark - NSCopying/NSObject
- (id)copyWithZone:(NSZone *)zone {}
- (NSString *)description {}
二、命名
1、变量和方法名:驼峰命名;
2、宏和常量命名
-
#define
预处理定义的常量全部大写,单词间用 _ 分隔例子: #define THIS_IS_AN_MACRO @”THIS_IS_AN_MACRO”
-
宏定义的本质是在编译时进行替换,所以宏定义中如果包含表达式或变量,表达式或变量必须用小括号括起来,防止与其他变量出现混合的情况。
3、枚举:枚举类型参考系统应该写全类型:名称+类型
typedef NS_ENUM(NSInteger, UIViewAnimationTransition) {
UIViewAnimationTransitionNone,
UIViewAnimationTransitionFlipFromLeft,
UIViewAnimationTransitionFlipFromRight,
UIViewAnimationTransitionCurlUp,
UIViewAnimationTransitionCurlDown,
};
当在switch使用枚举类型时,’default’是不需要的
4、类的命名:
ViewController: 使用ViewController做后缀,例子: XXHomeViewController
View: 使用View做后缀,例子: XXAlertView
UITableCell:使用Cell做后缀,例子: XXNewsCell
Protocol: 使用Delegate或者DataSource作为后缀,例子: UITableViewDelegate
UI控件依次类推
三、编码
1、字面编码
NSString
, NSDictionary
, NSArray
, 和 NSNumber
可以在创建不可变值时使用,注意不要传nil值,否则会崩溃。
NSArray *names = @[@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul"];
NSDictionary *productManagers = @{@"iPhone": @"Kate", @"iPad": @"Kamal", @"Mobile Web": @"Bill"};
NSNumber *shouldUseLiterals = @YES;
NSNumber *buildingStreetNumber = @10018;
2、条件语句
条件语句主体为了防止出错应该使用大括号包围,即使条件语句主体能够不用大括号编写(如,只用一行代码)。这些错误包括添加第二行代码和期望它成为if语句;还有,可能发生在if语句里面一行代码被注释了,然后下一行代码不知不觉地成为if语句的一部分。除此之外,这种风格与其他条件语句的风格保持一致,所以更加容易阅读。
// 应该
if (!error) {
return success;
}
// 而不是
if (!error)
return success;
// 或者
if (!error) return success;
3、构造方法/init方法
当构造方法被使用时,虽然用id也可以通过编译,但它应该返回类型是instancetype
而不是id
。这样确保编译器正确地推断结果类型。
- (instancetype)init {
self = [super init];
if (self) {
// ...
}
return self;
}
四、变量和属性
建议使用属性而不是实例变量。
推荐:
@interface RWTTutorial : NSObject
@property (strong, nonatomic) NSString *tutorialName;
@end
self.tutorialName
不推荐:
@interface RWTTutorial : NSObject {
NSString *tutorialName;
}
self->tutorialName
- 属性会自动有Setter和Getter,可以通过直接用点语法访问Setter和Getter方法。
- 虽然 和 ->是等价的,或者说编译器优化后等价。但是在访问空指针和野指针时有差别——空指针会挂在*解引用,野指针会挂在.访问内存。
五、常量
共享一块内存空间,就算项目中N处用到,也不会分配N块内存空间,可以根据const修饰的位置设定能否修改,在编译阶段会执行类型检查
推荐使用const来定义常量,如下
NSString *const kWEGMomentTopicNumberUpdateNotification = @"kWEGMomentTopicNumberUpdateNotification";
const不能满足的情况再考虑使用宏定义
#define kWEGMomentTopicNumberUpdateNotification @"kWEGMomentTopicNumberUpdateNotification"
如果是需要外部共享,使用extern关键字,参考苹果官方
extern NSString * const UIApplicationDidEnterBackgroundNotification
extern NSString * const UIApplicationWillEnterForegroundNotification
extern NSString * const UIApplicationDidFinishLaunchingNotification;
六、整体架构
推荐MVC+VM(也叫MVCS,S是Store的意思,数据处理逻辑)。
MVC+VM:MVC是苹果官方推荐,V专注于视图构建,Model是瘦Model,专注于模型构建,仅持有数据;数据流动全部由Controller来传递,流向清晰,当Controller变复杂时,将数据处理逻辑剥离出来成为VM,模型数据流向仍由Controller负责,优点是数据流向清晰,业务耦合弱,缺点是不同Controller可能要生成各种不同VM适配。
MVVM:主要优点数据绑定,做到数据一致性,同时也能做到给Controller瘦身目的,缺点是数据绑定导致数据流向不清晰,难以调试Bug,如果没有详细清晰文档,很可能成为一个天坑(助手里的聊天模块)。
MVP:Presenter与Controller相互持有,通过接口,P层拥有了Controller的权利,所有的业务分配都在P层内完成,包括像tableView的数据源和代理。优点是MVC解耦,MVC成为平行;缺点是,有点特意为了解耦而解耦,初看会莫名其妙。
一份分享