Objective-C编码规范补充

1、使用预编译指令#pragma mark组织代码

(1) 视图或控制器生命周期相关的代码

#pragma mark - Life Cycle

- (void)dealloc {}

- (instancetype)init {}

- (void)viewDidLoad {}

- (void)viewWillAppear:(BOOL)animated {}

- (void)viewDidAppear:(BOOL)animated {}

- (void)viewWillDisappear:(BOOL)animated {}

- (void)viewDidDisappear:(BOOL)animated {}

(2)通知相关的代码

#pragma mark - Notifications

- (void)addNotifications {}

- (void)removeNotifications {}

- (void)applicationDidEnterBackgroundNotification:(NSNotification *)notification {}

(3)事件响应相关代码

#pragma mark - Event Responses

- (void)actionForSettingButton:(UIButton *)button {}

- (void)actionForTapGestureRecognizer:(UITapGestureRecognizer *)tap {}

(4)协议相关的代码

#pragma mark - UIScrollViewDelegate

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {}

- (void)scrollViewDidZoom:(UIScrollView *)scrollView {}

(5)私有的辅助方法

#pragma mark - Helper

- (NSString *)titleForItemAtIndex:(NSUInteger)index {}

(6)Setter与Getter方法

#pragma mark - Accessors

- (UIImageView *)imageView
{
    if (_imageView) { return _imageView; }
    _imageView = [UIImageView new];
    return _imageView;
}

2、注释

(1)头文件对外公开的属性、方法、变量、枚举、常量使用统一的注释(快捷键alt + command + /)

/**
 按钮上显示的标题
 */
@property (nonatomic, copy) NSString *title;


/**
 图片编辑完成回调方法

 @param vc 图片编辑控制器
 @param result 图片编辑结果
 */
- (void)photoEditViewController:(TuSDKICViewController *)vc didCompleteWithResult:(TuSDKResult *)result;

(2)实现文件中关键代码或需要特别说明的代码要添加注释

3、属性声明

属性修饰符书写顺序:原子性,读写权限,内存管理,别名。另外注意weak、copy、readonly修饰符的使用。

@property (nonatomic, weak) id delegate;
@property (nonatomic, assign) NSUInterger selectedIndex;
@property (nonatomic, readonly) UIView *view;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) void (^completionHandler)();
@property (nonatomic, strong) NSArray *imageViews;

4、instancetype

对于明确返回类实例的方法,其返回类型应使用instancetype代替id类型。

5、命名

方法命名时谨慎使用前缀alloc/init/copy/mutableCopy/new/set/get

编译器约定,对于alloc/init/copy/mutableCopy/new这几个家族的方法,声明后面默认加NS_RETURNS_RETAINED标识;而其他方法默认添加NS_RETURNS_NOT_RETAINED标识。

系统自动生成的属性设置方法是以set开头的,另外可能对KVC查找键名称会有影响。

根据苹果推荐的命名规范,一般避免使用get作为方法名前缀。

6、使用预编译指令忽略特定的警告

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"

//确定这里不会发生内存泄漏时,使用预编译指令忽略警告
[myObj performSelector:mySelector withObject:name];

#pragma clang diagnostic pop

7、注意block的循环引用

(1)block本身没有被作为属性引用的情况

[UIView animateWithDuration:0.25 animations:^{
    self.view.alpha = 0;
}];

NSInteger (^setIndexBlock)(NSInteger, NSInteger) = ^(NSInteger a, NSInteger b) {
    self.index = a + b;
    return a + b;
};
setIndexBlock(1, 2);

(2)block被作为属性引用的情况1

比如block只会在主线程执行,或block内部只有一条语句:

__weak typeof(self) weakSelf = self;
backButton.clickBlock = ^{
    [weakSelf popViewControllerAnimated:YES];
};

(3)block被作为属性引用的情况2

比如block同时被多个对象引用,并且在子线程执行,则有可能在block执行过程中weakSelf变成nil:

__weak typeof(self) weakSelf = self;
myObj.myBlock =  ^{
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf)
    {
      [strongSelf doSomething];
      [strongSelf doSomethingElse];
    }
};

(4)主动解除循环引用

对于大部分情况,通过弱引用可以避免发生循环引用。但有些场合由于需求不能使用弱引用,即要求被引用的对象在block执行完成前不允许被释放,这种情况只要能保证block一定会被执行到,则可以在block内部主动解除循环引用。

self.myBlock = ^{
    NSLog(@"%@", self);
    self.myBlock = nil;
};

(5)其他

两个常用的宏定义:

#define weakify(o) __weak typeof(o) weakObj = o;
#define strongify(o) __strong typeof(o) strongObj = o;

weakify(self)
self.myBlock = ^{
    NSLog(@"%@", weakObj);
    strongify(weakObj)
    NSLog(@"%@", strongObj);
};

8、避免if语句多层嵌套

// 不推荐写法
if (condition1)
{
    if (condition2)
    {
        if (condition3)
        {
            //doSomething
        }
    }
}

// 推荐写法  
if (!condition1) { return; }
    
if (!condition2) { return; }
    
if (!condition3) { return; }
    
//doSomething

9、工程目录组织结构

一般工程目录主要结构:

  • MyProject:项目代码
  • MyProjectTests:单元测试代码
  • Frameworks:系统框架
  • Pods:第三方框架

项目代码目录MyProject:

  • Main

包括main文件、AppDelegate、定制的ViewController基类、TabBarController等整个应用结构相关,与具体功能无关的代码文件。

  • Common

放置应用中全局功能相关的代码文件,比如启动闪屏、登录、帐号系统、消息推送等。

  • Module1..n

通常按照TabBar上功能模块划分的一个模块。

  • Categories

放置所有的分类。

  • Utilities

放置工具类,比如网络工具、数据库工具、缓存管理工具等。

  • Venders

放置所有第三方库文件。

  • Resources

放置全局的资源类文件,比如plist文件、图片资源、视频音频文件、pch文件、JSON文件等。

每个功能模块下,比如Module1,可以根据不同子功能建立不同的子目录。目录中的文件包括该功能相关的全部文件,不包括一些全局或公共的文件,目录内不再划分view/viewController/model。目的是将代码尽量按照功能进行组织,而不是按照类型。另外,工程中的group应与实际目录一一对应。

Objective-C编码规范补充_第1张图片
工程目录结构示例
Objective-C编码规范补充_第2张图片
功能模块子目录示例

参考资料:

  • 《禅与Objective-C编程艺术》https://objc-zen-book.books.yourtion.com/

  • 《纽约时报移动团队Objective-C编码规范》https://github.com/NYTimes/objective-c-style-guide/blob/master/README_zh-Hans.md

  • 《Effective Objective-C 2.0》

你可能感兴趣的:(Objective-C编码规范补充)