内容简介:在平常的项目开发中,经常会遇到几乎大多数程序员都是与团队内的其他成员合作完成一个项目,即使是自己独立开发一个项目,一个模块调用另外一个模块,都需要一个清晰明确的接口规范。当面对多个初始化方法时,外部调用者可能手无足措,不知道哪一个才是正确的初始化方法。为此苹果提供了两个关键字:一般都希望外部调用接口的时候,传入一些基本的参数用来初始化。而不希望使用默认的初始化方法,因此我们可以这么做:
日常开发中遇到的问题:
在平常的项目开发中,经常会遇到 多人同时开发一个需求 的场景。同事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、 :warning::Method override for the designated initializer of the superclass '-init' not found
(没有找到父类的指定初始化方法)
2、 :warning::Convenience initializer missing a 'self' call to another initializer
(便利初始化方法需要调用另外一个初始化方法)
重写父类的指定初始化方法后,不能调用super相关的方法。否则会报类似警告:
:warning::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
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- golang init方法和main方法初始化顺序
- iOS 指定初始化方法
- 在 Java 中初始化 List 的五种方法
- java编程——从jvm角度看懂类初始化、方法重写、重载
- Scala – 在已经声明的数组中初始化值的最优雅的方法?
- 不用批归一化也能训练万层ResNet,新型初始化方法Fixup了解一下
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
解放战争(上)(1945年8月—1948年9月)
王树增 / 人民文学出版社 / 2009-8 / 60.00
《解放战争》为王树增非虚构文学著述中规模最大的作品。武器简陋、兵力不足的军队对抗拥有现代武器装备的兵力庞大的军队,数量不多、面积有限的解放区最终扩展成为九百六十万平方公里的共和国,解放战争在短短四年时间里演绎的是人类历史上的战争传奇。国际风云,政治智慧,时事洞察,军事谋略,军队意志,作战才能,作品具有宏阔的视角和入微的体察,包含着惊心动魄的人生沉浮和变幻莫测的战场胜负,尽展中国历史上规模最大的一场......一起来看看 《解放战争(上)(1945年8月—1948年9月)》 这本书的介绍吧!