close
当前位置: 物联网在线 > 技术文库 > ios >

iOS 创建对象的姿势

在写 iOS 代码的时候,怎么样去 new 一个新对象出来,都有一些讲究在里面。使用不同的姿势去创建对象,对后期维护所造成的影响会存在细微的差别。

init 创建

在之前一篇分析 iOS 代码耦合的文章中,提到过当我们给一个对象的 property 赋值的时候,通过 init 方法传入参数来初始化 property 会让我们的代码更可靠。

有些人在定义带 property 的 class 的时候,会这样定义:

@interface User : NSObject @property (nonatomic, strong) NSNumber* userID; @end

使用的时候如下:

User* user = [[User alloc] init]; user.userID = @1000;

尤其是在定义 model 的时候,很容易写出这种,先 init,而后挨个给 property 赋值的代码。这种代码的问题在于 property 对于外部是可写的,property 处于随时可能变化的状态。之前不少篇文章中都强调过 immutable 的重要性,同样对于一个 class,我们也应该优先考虑设计成 immutable 的。

initWith 创建

如果将 property 都设置成 readonly 的,或者不暴露 property,property 的赋值都通过 initWith 的方式来初始化,就可以得到一个具备 immutable 的 class 定义了,具体到上面的例子代码如下:

//User.h @interface User : NSObject @property (nonatomic, strong, readonly) NSNumber* userID; - (instancetype)initWithUserID:(NSNumber*)uid; @end //User.m @implementation User - (instancetype)initWithUserID:(NSNumber*)uid { self = [super init]; if (!self) { return nil; } _userID = uid; return self; } @end

userID 在 .h 文件当中是 readonly 的,userID 只有一次被赋值的机会,即在 User 的 initWith 方法中。这种方式的好处是一旦 User 对象创建完毕之后,就处于 immutable 的状态,property 都是不可修改的,安全可靠。

Designated initializer

Apple 为了方便开发者使用 init 方法,引入了一种名为 designated initializer 的 pattern。主要用来管理当一个 class 拥有多个 property 需要赋值的场景。比如上面我们的 User 类:

@interface User : NSObject @property (nonatomic, strong, readonly) NSNumber* userID; @property (nonatomic, strong, readonly) NSString* userName; @property (nonatomic, strong, readonly) NSString* signature; @end

有些场景需要初始化 userID 和 userName,而有些场景只需要初始化 userID 和 signature,所以我们需要提供多个 initWith 方法给不同的场景使用。为了管理 initWith 方法,Apple 将 init 方法分为两种类型:designated initializer 和 convenience initializer (又叫 secondary initializer) 。

designated initializer 只有一个,它会为 class 当中每个 property 都提供一个初始值,是最完整的 initWith 方法。convenience initializer 则可以有很多个,它可以选择只初始化部分的 property。convenience initializer 最后到会调用到 convenience initializer,所以 convenience initializer 也可以叫做 final initializer。

无论我们定义何种类型的 class,给 class 中的每个 property 都赋予一个初始值是个很好的习惯,可以避免掉一些意外的 bug 产生,这也是 designated initializer 的重要职责。

在实际的项目当中,一个 class 的 property 数目可能会随着业务的增长而增加,最后的结果就是会生成越来越多的 convenience initializer。上述的 User 类,如果是 3 个 property,极端的情况下最多可以有 7 个 init 方法。Peak君在阅读代码的时候,也确实看到过有些 class 定义了一连串整整齐齐摆放的 init 方法,代码虽然看着规范,但显得啰嗦,而且每次需要肉眼搜索适合的 init 方法。

其实我们还可以用另一种姿势来 init 我们的对象。

Builder pattern

最初是在学习 Android 的时候,发现这个 builder pattern 也可以用来构建对象,而且可以很好的解决 init 方法过多难以管理的问题。先来看下如何实现,顾名思义,builder pattern 使用另一个名为 builder 的类来创建我们的目标对象,还是上面的例子,代码如下:

//UserBuilder.h @interface UserBuilder : NSObject @property (nonatomic, strong, readonly) NSNumber* userID; @property (nonatomic, strong, readonly) NSString* userName; @property (nonatomic, strong, readonly) NSString* signature; - (UserBuilder*)userID:(NSNumber*)userID; - (UserBuilder*)userName:(NSString*)userName; - (UserBuilder*)signature:(NSString*)signature; @end //UserBuilder.m @implementation UserBuilder - (UserBuilder*)userID:(NSNumber*)userID { _userID = userID; return self; } - (UserBuilder*)userName:(NSString*)userName { _userName = userName; return self; } - (UserBuilder*)signature:(NSString*)signature { _signature = signature; return self; } @end

接下来 User 的 init 方法从 Builder 中获取 property 的初始值:

//User.h @interface User : NSObject @property (nonatomic, strong, readonly) NSNumber* userID;@property (nonatomic, strong, readonly) NSString* userName;@property (nonatomic, strong, readonly) NSString* signature; - (instancetype)initWithUserBuilder:(UserBuilder*)builder; @end //User.m @implementation User - (instancetype)initWithUserBuilder:(UserBuilder*)builder { self = [super init]; if (!self) { return nil; } _userID = builder.userID; _userName = builder.userName; _signature = builder.signature; return self; } @end
(责任编辑:ioter)

用户喜欢...

使用DLP技术创建高分辨率自适应大灯

传统上,典型的汽车前照灯光束仅照亮车辆前方的物体,以提高驾驶员在低光照和恶劣天气条件下的可视性。低光束在车辆前方短距离照亮道路,而远光灯具有更长的范围和更宽的角度。这种...


创建最终的嵌入式软件工作台

及时高效地构建嵌入式系统要求软件开发人员在其工作台上有合适的工具来完成工作。虽然预算通常是有限的,但是每个嵌入式软件工程师都需要一些工具来大大减少构建,调试和验证设计所需...


Vivado中AXI IP核的创建和读写逻辑分析

本文包含两部分内容:1)AXI接口简介;2)AXI IP核的创建流程及读写逻辑分析。 1AXI简介(本部分内容参考官网资料翻译) 自定义IP核是Zynq学习与开发中的难点,AXI IP核又是十分常用的自定义...


Unity应用架构设计(8)——使用ServiceLocator实现对象的注入

对象的 『注入』 是企业级软件开发经常听到的术语。如果你是一个 Java 程序员,一定对注入有着深刻的映像。不管是SSH框架还是SSM框架,Spring 全家桶永远是绕不过去的弯。通过依赖注入,可...


符合IBM IoT Platform标准的设备被成功创建,与此同时还创建了一个API密钥

前言 本文将详细说明使用IBM Waston IoT Platform创建物联网设备的具体步骤。IBM Waston IoT Platform是IBM Bluemix云计算的一部分,是专门为物联网设计的系统之一,该平台支持HTTP和MQTT。学习IBM Bluemix和...


自动驾驶时代汽车如何安全旅行?看生物识别技术的落地姿势

随着汽车产业逐步朝着电动化和自动驾驶的方向发展,媒体已经开始对这些新技术在汽车上的应用给予了大量关注。不过除此之外,还有一项令人兴奋的进步发生在汽车上,那就是汽车生物识...


3D打印怪事:科学家们用水和机器人来创建3D扫描技术

3D扫描过程可能很棘手,特别是当您处理包含裂缝和其他隐藏部分的对象时。以色列内盖夫本古里安大学的研究人员...


涨姿势!市场上主流的ARM产品分析,以及开发环境介绍

ARM CPU现在分为3种型号: A系列:主要是用在智能手机上,代表的系统是Andrios和IOS。 R系列:和M系列一样,更注重实时功能,军工和航天的实时嵌入式设备 arm+ucos或者arm+vxWorks M系列:类似于...


使用Maker Touchscreen创建多彩的用户界面

为制造商社区设计的微处理器板不仅吸引了热衷于进入电子​​世界的发明家的想象力,还吸引了专业工程师的想象力。大型工程组织的独立顾问,新创企业和团队在开发新产品时都面临着时间...


详解苹果Core ML:如何为iOS创建机器学习应用?

在昨天开幕的 WWDC 2017 开发者大会上,苹果宣布了一系列新的面向开发者的机器学习 API,包括面部识别的视觉 API、自然语言处理 API,这些 API 集成了苹果所谓的 Core ML 框架;参阅机器之心报...