@(iOS开发学习)[温故而知新]程序员
1、Objective-C基本套路编程
2、Objective-C细枝末节swift
3、Swift中的指定构造方法和便利初始化方法安全
3.一、为什么要初始化?bash
3.二、类初始化的几种方法ide
- 3.2.一、Designated
- 3.2.二、convenience
- 3.2.三、required
平常开发中遇到的问题:函数
在日常的项目开发中,常常会遇到多人同时开发一个需求的场景。同事A提供了自定义初始化方法,可是同事B却调用了默认的初始化方法,由于同事A在自定义初始化方法中作了一些特殊操做,致使同事B使用默认初始化方法却没有达到预期的效果,而后又浪费了不少精力与同事A进行沟通查找问题。学习
几乎大多数程序员都是与团队内的其余成员合做完成一个项目,即便是本身独立开发一个项目,一个模块调用另一个模块,都须要一个清晰明确的接口规范。当面对多个初始化方法时,外部调用者可能手无足措,不知道哪个才是正确的初始化方法。为此苹果提供了两个关键字:
NS_UNAVAILABLE
与NS_DESIGNATED_INITIALIZER
来帮助咱们约束对象的初始化方法,使得接口描述更加清晰。ui
NS_DESIGNATED_INITIALIZER
:用来将修饰的方法标记为指定构造器atom
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"];
复制代码
当想让调用者调用本身的构造方法的时候,就能够在.h文件中将本身的构造方法使用
NS_DESIGNATED_INITIALIZER
修饰
当不想让调用者调用父类的构造函数的时候,就能够在.h文件中将父类的构造方法使用
NS_UNAVAILABLE
修饰
若是子类实现了
NS_DESIGNATED_INITIALIZER
修饰的指定初始化方法,没有使用NS_UNAVAILABLE
修饰父类的初始化方法。则须要在子类重写父类的指定初始化方法,而且在里面调用子类本身的指定初始化方法。由于若是一个类的方法被NS_DESIGNATED_INITIALIZED
修饰,则改方法变成指定构造方法,从父类继承来的指定构造方法则变成便利初始化方法。 子类没有重写父类的指定初始化方法会报相似警告:一、
⚠️:Method override for the designated initializer of the superclass '-init' not found
(没有找到父类的指定初始化方法)二、
⚠️: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
先初始化本身的成员变量,而后在调用父类的初始化方法
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)
}
}
复制代码
nil
初始化它。override
修饰。convenience
修饰的初始化方法必须调用一个其余初始化方法。convenience
必须最终调用一个指定的初始化方法。convenience
修饰的方便初始化方法,不须要加override
关键字。required
修饰的方法