iOS开发规范篇:清晰的初始化方法
@(iOS开发学习)[温故而知新]
一、Objective-C基本套路
二、Objective-C细枝末节
三、Swift中的指定构造方法和便利初始化方法
3.1、为何要初始化?
3.2、类初始化的几种方法
- 3.2.1、Designated
- 3.2.2、convenience
- 3.2.3、required
一、Objective-C基本套路
日常开发中遇到的问题:
在平常的项目开发中,经常会遇到多人同时开发一个需求的场景。同事A提供了自定义初始化方法,但是同事B却调用了默认的初始化方法,因为同事A在自定义初始化方法中做了一些特殊操作,导致同事B使用默认初始化方法却没有达到预期的效果,然后又浪费了很多精力与同事A进行沟通查找问题。
几乎大多数程序员都是与团队内的其他成员合作完成一个项目,即使是自己独立开发一个项目,一个模块调用另外一个模块,都需要一个清晰明确的接口规范。当面对多个初始化方法时,外部调用者可能手无足措,不知道哪一个才是正确的初始化方法。为此苹果提供了两个关键字:
NS_UNAVAILABLE
与NS_DESIGNATED_INITIALIZER
来帮助我们约束对象的初始化方法,使得接口描述更加清晰。
NS_DESIGNATED_INITIALIZER
:用来将修饰的方法标记为指定构造器NS_UNAVAILABLE
:禁止使用某个初始化方法
一般都希望外部调用接口的时候,传入一些基本的参数用来初始化。而不希望使用默认的初始化方法,因此我们可以这么做:
@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
+ (instancetype)new NS_UNAVAILABLE;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithName:(NSString*)name NS_DESIGNATED_INITIALIZER;
@end@implementation Person
- (instancetype)initWithName:(NSString *)name {if ( self = [super init] ) {self.name = name;}return self;
}
@end
复制代码
当创建一个Person对象的时候,不能使用
NS_UNAVAILABLE
修饰的[Person new]
和[[Person alloc]init]
方法,而应该使用NS_DESIGNATED_INITIALIZER
修饰的- (instancetype)initWithName:(NSString*)name
方法。
// Xcode报错:'new' is unavailable
Person* person1 = [Person new];
// Xcode报错:'init' is unavailable
Person* person2 = [[Person alloc]init];
// 正确
Person* person3 = [[Person alloc]initWithName:@"XiaoMing"];
复制代码
二、Objective-C细枝末节
当想让调用者调用自己的构造方法的时候,就可以在.h文件中将自己的构造方法使用
NS_DESIGNATED_INITIALIZER
修饰
当不想让调用者调用父类的构造函数的时候,就可以在.h文件中将父类的构造方法使用
NS_UNAVAILABLE
修饰
如果子类实现了
NS_DESIGNATED_INITIALIZER
修饰的指定初始化方法,没有使用NS_UNAVAILABLE
修饰父类的初始化方法。则需要在子类重写父类的指定初始化方法,并且在里面调用子类自己的指定初始化方法。因为如果一个类的方法被NS_DESIGNATED_INITIALIZED
修饰,则改方法变成指定构造方法,从父类继承来的指定构造方法则变成便利初始化方法。 子类没有重写父类的指定初始化方法会报类似警告:1、
⚠️:Method override for the designated initializer of the superclass '-init' not found
(没有找到父类的指定初始化方法)2、
⚠️:Convenience initializer missing a 'self' call to another initializer
(便利初始化方法需要调用另外一个初始化方法)重写父类的指定初始化方法后,不能调用super相关的方法。否则会报类似警告:
⚠️:Convenience initializer should not invoke an initializer on 'super'
(便利初始化方法不能调用super初始化方法)
避免使用
new
创建对象,从安全和设计角度来说我们应该对初始化所有属性,提高程序的健壮性和复用性。不论是何种情况,在类中至少包含一个构造函数是一种很好的编程实践,如果类中有属性,好的实践往往是初始化这些属性。 ——以上摘自
《The Object-Oriented Thought Process》
by Matt Weisfeld
术语区分:
构造方法
vs初始化方法
严格意义上
Objective-c
是没有构造函数
的,我们所说的都是初始化方法,创建对象(alloc
)之后调用实例的初始化方法initWithXXX
。
构造方法
的写法:类名(参数列表...)
构造方法
是一种特殊的方法,它是一个与类同名且返回值类型为同名类类型的方法。对象的创建就是通过构造方法来完成,其功能主要是完成对象的初始化。当类实例化一个对象时会自动调用构造方法。构造方法和其他方法一样也可以重载。
Objective-C与swift的初始化顺序的区别:
Objective-C
先调用父类的初始化方法,然后初始自己的成员变量
swift
先初始化自己的成员变量,然后在调用父类的初始化方法
三、Swift中的指定构造方法和便利初始化方法
class People {var name: String?// 在swift中属性不是可选类型的都必须初始化var age: Int// 指定初始化方法前面不需要添加修饰init() {age = 0}// 便利初始化方法前面需要添加convenience修饰convenience init(name: String) {self.init()self.name = name}
}
class Man: People {var mustacheLength: Int// 子类重写父类的指定初始化方法,需要使用override修饰override init() {self.mustacheLength = 0}// 便利初始化方法一:内部调用指定初始化方法convenience init(mustacheLength: Int) {self.init()self.mustacheLength = mustacheLength// 修改父类的属性值必须在子类的便利初始化方法内部调用完指定初始化方法后self.age = 1}// 便利初始化方法二:内部调用其他便利初始化方法,但是最后一个便利初始化方法内部还是要调用指定初始化方法convenience init(mustacheLength: Int, name: String = "") {self.init(mustacheLength: mustacheLength)}
}
复制代码
3.1、为何要初始化?
- 系统要求存储属性必须初始化
- 结构体系统默认会添加初始化方法,当然自己也可以自定义
3.2、类初始化的几种方法
3.2.1、Designated
- 可选值可以不用初始化,如果不初始化值,系统默认用
nil
初始化它。 - 如果类中含有非可选的存储属性并且没有默认值,则必须实现指定初始化方法,并且初始化该属性。
- 如果子类没有自己的初始化方法,系统默认使用父类的初始化方法,一旦有了自己的初始化方法,或者重写了父类的初始化方法,则父类的所有初始化不能被子类调用。
- 你可以给子类添加和父类相同的初始化方法,但需要加上
override
修饰。
3.2.2、convenience
- 在同一个类,使用
convenience
修饰的初始化方法必须调用一个其他初始化方法。 convenience
必须最终调用一个指定的初始化方法。- 重写父类的
convenience
修饰的方便初始化方法,不需要加override
关键字。
3.2.3、required
- 子类必须重写父类用
required
修饰的方法 - 可以和convenience组合使用
参考资料
NS_UNAVAILABLE 与 NS_DESIGNATED_INITIALIZER
Swift 初始化(Initialization)
Swift-init初始化方法
iOS开发规范篇:清晰的初始化方法相关推荐
- iOS开发UI篇 -- UISearchBar 属性、方法详解及应用(自定义搜索框样式)
很多APP都会涉及到搜索框,苹果也为我们提供了默认的搜索框UISearchBar.但实际项目中我们通常需要更改系统默认搜索框的样式.为了实现这一目标,我们需要先搞懂 UISearchBar 的属性及方 ...
- iOS开发UI篇—UITableview控件使用小结
iOS开发UI篇-UITableview控件使用小结 一.UITableview的使用步骤 UITableview的使用就只有简单的三个步骤: 1.告诉一共有多少组数据 方法:- (NSInteger ...
- iOS开发UI篇—使用xib自定义UItableviewcell实现一个简单的团购应用界面布局
iOS开发UI篇-使用xib自定义UItableviewcell实现一个简单的团购应用界面布局 iOS开发UI篇-使用xib自定义UItableviewcell实现一个简单的团购应用界面布局 一.项目 ...
- iOS开发规范学习总结与框架搭建
iOS 开发规范 以MVC开发模式为主,根据模块化+MVC思想 一.模块化思想创建目录路径(创建真实路径,再拖到项目中不要直接创建Group) M -- 模型,模型对象封装了应用程序的数据,并定义操控 ...
- iOS开发UI篇—transframe属性(形变)
iOS开发UI篇-transframe属性(形变) 1. transform属性 在OC中,通过transform属性可以修改对象的平移.缩放比例和旋转角度 常用的创建transform结构体方法分两 ...
- iOS开发UI篇—多控制器和导航控制器简单介绍
iOS开发UI篇-多控制器和导航控制器简单介绍 一.多控制器 一个iOS的app很少只由一个控制器组成,除非这个app极其简单.当app中有多个控制器的时候,我们就需要对这些控制器进行管理 有多个vi ...
- iOS开发UI篇—UIWindow简单介绍
iOS开发UI篇-UIWindow简单介绍 一.简单介绍 UIWindow是一种特殊的UIView,通常在一个app中只会有一个UIWindow iOS程序启动完毕后,创建的第一个视图控件就是UIWi ...
- iOS开发UI篇—UITableviewcell的性能优化和缓存机制
iOS开发UI篇-UITableviewcell的性能问题 一.UITableviewcell的一些介绍 UITableView的每一行都是一个UITableViewCell,通过dataSource ...
- iOS开发拓展篇——如何把项目托管到GitHub
iOS开发拓展篇--如何把项目托管到GitHub 说明:本文主要介绍如何把一个OC项目托管到Github,重操作轻理论. 第一步:先注册一个Github的账号,这是必须的 注册地址:Github官网注 ...
- IOS开发数据库篇—SQLite模糊查询
IOS开发数据库篇-SQLite模糊查询 一.示例 说明:本文简单示例了SQLite的模糊查询 1.新建一个继承自NSObject的模型 该类中的代码: 1 // 2 // YYPerson.h 3 ...
最新文章
- Linux7 下重新安装YUM
- from flask.ext.cache import make_template_fragment_key
- 关于举办XX学院“XX杯”网页设计大赛的通知
- 正则表达式(不断更新,欢迎纠错)
- java接口开发规范,干货满满
- Kotlin学习笔记 第四章注解
- LINQ-查询表达式基础
- 第十七周项目2-引用作形参
- adodb.recordset.open方法的参数
- WebLogic 服务器概述 与 部署 Java Web 应用
- Gstreamer插件编译安装的Makefile
- YUI Compressor Maven
- 【速度↑20%模型尺寸↓36%】极简开源人脸检测算法升级
- MATLAB实现一组随机点分成两组,每组随机点分别与一个特定点连线
- RFID图书馆管理系统
- 基于MATLAB/Simulink的电力电子电路仿真技术——直流降压(Buck)变换器及Powergui的使用
- chm提示 已取消到该网页的导航的解决方法
- 云呐|常用的固定资产盘点方法有哪些
- mt6739耳机通道配置外置功放
- Kindle可用三方字体的书籍格式