iOS Development Guidelines
  • Introduction
  • 规范
    • 0. 介绍
    • 1. 序言
    • 2. 代码命名规范
      • 2.1. 代码命名基础
      • 2.2. 方法(Method)命名
      • 2.3. 函数(Function)命名
      • 2.4. 属性(Property)与数据类型命名
      • 2.5. 其它命名规范
      • 2.6. 可接受缩略名
    • 3. 代码格式规范
      • 3.1. 代码注释格式
      • 3.2. 代码结构与排版
    • 4. 开发实践
      • 4.1. Objective-C保留字
    • 5. Xcode工程结构
    • 6. 版本控制
      • 6.1. Git基本配置
      • 6.2. Git分支模型
      • 6.3. SVN源代码管理规范
      • 6.4. SVN的标准目录结构
    • 7. 附录
      • 7.1. Xcode扩展插件
      • 7.2. 第三方开源库
    • 8. 参考
    • 9. iOS开发优化
  • Swift编码规范
  • Objective-C新特性
  • iOS生命周期
  • Apple 官方设计指南
    • iOS 人机交互指南
      • 概览 - 设计理念
      • 概览 - iOS 10 新功能
      • 概览 - 接口要素
      • 交互 - 3D Touch
      • 交互 - 辅助功能
      • 交互 - 音频
      • 交互 - 身份验证
      • 交互 - 数据输入
      • 交互 - 反馈
      • 交互 - 文件处理
      • 交互 - 初次启动体验
      • 交互 - 手势
      • 交互 - 加载
      • 交互 - 模态
      • 交互 - 导航
      • 交互 - 评分和评论
      • 交互 - 请求权限
      • 交互 - 设置
      • 交互 - 术语
      • 交互 - 撤销与重做
      • 系统功能 - 多任务
      • 系统功能 - 通知
      • 系统功能 - 打印
      • 系统功能 - 快速预览
      • 系统功能 - Siri
      • 系统功能 - TV 供应商
      • 可视化设计 - 动画
      • 可视化设计 - 品牌化
      • 可视化设计 - 颜色
      • 可视化设计 - 布局
      • 图像 - 应用图标
  • Apple 官方开发指南
    • App 发布指南
      • 待完善
    • Cocoa 代码指南
      • 代码命名基础
      • 方法命名
      • 函数命名
      • 属性和数据类型命名
      • 可接受的缩写词和首字母缩写词
      • 针对框架开发者的技术细节
    • 核心蓝牙编程指南
      • 待完善
  • iOS 杂谈
    • Auto Layout 是怎么进行自动布局的性能如何
    • App 启动速度的优化与监控
    • 多人的大项目,架构怎么设计更合理
    • 链接器:符号是怎么绑定到地址上的
    • App 如何通过注入动态库的方式实现极速编译调试
    • 静态分析工具的选择
    • Clang的App 提质
    • 无侵入的埋点方案如何实现
    • 包大小:如何从资源和代码层面实现全方位瘦身
    • iOS 崩溃千奇百怪如何全面监控
    • 如何利用 RunLoop 原理去监控卡顿
    • 临近 OOM,如何获取详细内存分配信息,分析内存问题
    • 日志监控:怎样获取 App 中的全量日志
    • 性能监控:衡量 App 质量的那把尺
    • 远超想象的多线程的那些坑
    • 怎么减少 App 电量消耗
    • 除了 Cocoa,iOS还可以用哪些 GUI 框架开发
    • 细说 iOS 响应式框架变迁,哪些思想可以为我所用
    • 如何构造酷炫的物理效果和过场动画效果
    • A/B 测试:验证决策效果的利器
    • 怎样构建底层的发布和订阅事件总线
    • 如何提高 JSON 解析的性能
    • 如何用 Flexbox 思路开发?跟自动布局比,Flexbox 好在哪
    • 怎么应对各种富文本表现需求
    • 如何在 iOS 中进行面向测试驱动开发和面向行为驱动开发
    • 如何制定一套适合自己团队的 iOS 编码规范
    • iOS 系统内核 XNU:App 如何加载
    • iOS 黑魔法 Runtime Method Swizzling 背后的原理
    • libffi:动态调用和定义 C 函数
    • iOS 是怎么管理内存的
    • 如何编写 Clang 插件
    • 打通前端与原生的桥梁:JavaScriptCore 能干哪些事情
    • React Native、Flutter 等,这些跨端方案怎么选
    • 原生布局转到前端布局,开发思路有哪些转变
    • iOS原生、大前端和Flutter分别是怎么渲染的
    • 剖析使 App 具有动态化和热更新能力的方案
  • Flutter
    • 0.Flutter学习笔记以及问题记录
    • 1.Dart基础快速入门
    • 2.什么是声明式UI
    • 3.Flutter入门基础知识
    • 4.项目结构、资源、依赖和本地化
    • 6.布局与列表
    • 7.状态管理
    • 8.路由与导航
    • 9.手势检测及触摸事件处理
    • 9.线程和异步UI
    • 10.主题和文字处理
    • 11.表单输入与富文本
    • 12.调用硬件、第三方服务以及平台交互、通知
    • 13.基于Http实现网络操作
    • 14.图片控件开发详解
    • 15.异步:Future与FutureBuilder实用技巧
    • 16.APP首页框架搭建-Scaffold与PageView
Powered by GitBook
On this page
  • 初始化
  • 单例
  • 字面量
  • CGRect 函数
  • 常量
  • 枚举类型
  • 位掩码
  • 私有属性
  • 布尔值

Was this helpful?

  1. 规范

4. 开发实践

Previous3.2. 代码结构与排版Next4.1. Objective-C保留字

Last updated 5 years ago

Was this helpful?

本章主要描述开发过程中一些比较固定的实践技巧,写代码时可以直接套用

初始化

  • 初始化方法的返回类型用instancetype,不要用id

    关于instancetype的介绍参见。

单例

单例对象应该使用线程安全的模式创建共享的实例。

+ (instancetype)sharedInstance {
   static id sharedInstance = nil;
   static dispatch_once_t onceToken;
   dispatch_once(&onceToken, ^{
      sharedInstance = [[self alloc] init];
   });
   return sharedInstance;
}

这将会预防。

字面量

每当创建NSString,NSDictionary,NSArray,和NSNumber类的不可变实例时,都应该使用字面量。要注意nil值不能传给NSArray和NSDictionary字面量,这样做会导致崩溃。

推荐:

NSArray *names = @[@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul"];
NSDictionary *productManagers = @{@"iPhone" : @"Kate", @"iPad" : @"Kamal", @"Mobile Web" : @"Bill"};
NSNumber *shouldUseLiterals = @YES;
NSNumber *buildingZIPCode = @10018;

反对:

NSArray *names = [NSArray arrayWithObjects:@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul", nil];
NSDictionary *productManagers = [NSDictionary dictionaryWithObjectsAndKeys: @"Kate", @"iPhone", @"Kamal", @"iPad", @"Bill", @"Mobile Web", nil];
NSNumber *shouldUseLiterals = [NSNumber numberWithBool:YES];
NSNumber *buildingZIPCode = [NSNumber numberWithInteger:10018];

CGRect 函数

All functions described in this reference that take CGRect data structures as inputs implicitly standardize those rectangles before calculating their results. For this reason, your applications should avoid directly reading and writing the data stored in the CGRect data structure. Instead, use the functions described here to manipulate rectangles and to retrieve their characteristics.

推荐:

CGRect frame = self.view.frame;
CGFloat x = CGRectGetMinX(frame);
CGFloat y = CGRectGetMinY(frame);
CGFloat width = CGRectGetWidth(frame);
CGFloat height = CGRectGetHeight(frame);

反对:

CGRect frame = self.view.frame;
CGFloat x = frame.origin.x;
CGFloat y = frame.origin.y;
CGFloat width = frame.size.width;
CGFloat height = frame.size.height;

常量

  • 定义常量时,除非明确的需要将常量当成宏使用,否则优先使用const,而非#define

  • 只在某一个特定文件里面使用的常量,用static

    static CGFloat const RWImageThumbnailHeight = 50.0;

枚举类型

当使用enum时,建议使用新的基础类型规范,因为它具有更强的类型检查和代码补全功能。现在 SDK 包含了一个宏来鼓励使用新的基础类型NS_ENUM

typedef NS_ENUM(NSInteger, NYTAdRequestState) {
    NYTAdRequestStateInactive,
    NYTAdRequestStateLoading
};

位掩码

当用到位掩码时,建议使用NS_OPTIONS类型的宏

typedef NS_OPTIONS(NSUInteger, NYTAdCategory) {
    NYTAdCategoryAutos      = 1 << 0,
    NYTAdCategoryJobs       = 1 << 1,
    NYTAdCategoryRealState  = 1 << 2,
    NYTAdCategoryTechnology = 1 << 3
};

私有属性

私有属性应该声明在类实现文件的延展(匿名的类目)中。有名字的类目(例如ASMPrivate或private)永远都不应该使用,除非要扩展其他类。

@interface NYTAdvertisement ()

@property (nonatomic, strong) GADBannerView *googleAdView;
@property (nonatomic, strong) ADBannerView *iAdView;
@property (nonatomic, strong) UIWebView *adXWebView;

@end

布尔值

  • Objective-C的布尔值只使用YES和NO

  • true和false只能用于CoreFoundation,C或C++的代码中

  • 禁止将某个值或表达式的结果与YES进行比较

    因为BOOL被定义成signed char。这意味着除了YES(1)和NO(0)以外,它还可能是其他值。(32位系统)

    因此C或C++中的非0为真并不一定就是YES

    //以下都是被禁止的
    - (BOOL)isBold {
        return [self fontTraits] & NSFontBoldTrait;
    }

    - (BOOL)isValid {
        return [self stringValue];
    }

    if ([self isBold] == YES) {
        //...
    }


    //以下才是赞成的方式
    - (BOOL)isBold {
        return ([self fontTraits] & NSFontBoldTrait) ? YES : NO;
    }

    - (BOOL)isValid {
        return [self stringValue] != nil;
    }

    - (BOOL)isEnabled {
        return [self isValid] && [self isBold];
    }

    if ([self isBold]) {
        //...
    }
  • 虽然nil会被直接解释成NO,但还是建议在条件判断时保持与nil的比较,因为这样代码更直观。

    //比如,更直观的代码
    if (someObject != nil) {
        //...
    }

    //没那么直观的代码
    if (!someObject) {
        //...
    }
  • 在C或C++代码中,要注意NULL指针的检测。

    向一个nil的Objective-C对象发送消息不会导致崩溃。但由于Objective-C运行时不会处理给NULL指针的情况,所以为了避免崩溃,需要自行处理对于C/C++的NULL指针的检测。

  • 如果某个BOOL类型的property的名字是一个形容词,建议为getter方法加上一个"is"开头的别名。

    @property (assign, getter = isEditable) BOOL editable;
  • 在方法实现中,如果有block参数,要注意检测block参数为nil的情况。

    - (void)exitWithCompletion:(void(^)(void))completion {
        // 错误。 如果外部调用此方法时completion传入nil,此处会发生EXC_BAD_ACCESS
        completion();

        // 正确。如果completion不存在则不调用。
        if (completion) {
            completion();
        }
    }

当访问一个CGRect的x,y,width,height时,应该使用CGGeometry代替直接访问结构体成员。苹果的CGGeometry参考中说到:

NSHipster.com
有时可能产生的许多崩溃
函数