iOS开发规范篇:清晰的初始化方法

@(iOS开发学习)[温故而知新]程序员

1、Objective-C基本套路编程

2、Objective-C细枝末节swift

3、Swift中的指定构造方法和便利初始化方法安全

  • 3.一、为什么要初始化?bash

  • 3.二、类初始化的几种方法ide

    • 3.2.一、Designated
    • 3.2.二、convenience
    • 3.2.三、required

1、Objective-C基本套路

平常开发中遇到的问题:函数

在日常的项目开发中,常常会遇到多人同时开发一个需求的场景。同事A提供了自定义初始化方法,可是同事B却调用了默认的初始化方法,由于同事A在自定义初始化方法中作了一些特殊操做,致使同事B使用默认初始化方法却没有达到预期的效果,而后又浪费了不少精力与同事A进行沟通查找问题。学习


几乎大多数程序员都是与团队内的其余成员合做完成一个项目,即便是本身独立开发一个项目,一个模块调用另一个模块,都须要一个清晰明确的接口规范。当面对多个初始化方法时,外部调用者可能手无足措,不知道哪个才是正确的初始化方法。为此苹果提供了两个关键字:NS_UNAVAILABLENS_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"];
复制代码

2、Objective-C细枝末节

当想让调用者调用本身的构造方法的时候,就能够在.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先初始化本身的成员变量,而后在调用父类的初始化方法

3、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.一、为什么要初始化?

  • 系统要求存储属性必须初始化
  • 结构体系统默认会添加初始化方法,固然本身也能够自定义

3.二、类初始化的几种方法

3.2.一、Designated

  • 可选值能够不用初始化,若是不初始化值,系统默认用nil初始化它。
  • 若是类中含有非可选的存储属性而且没有默认值,则必须实现指定初始化方法,而且初始化该属性。
  • 若是子类没有本身的初始化方法,系统默认使用父类的初始化方法,一旦有了本身的初始化方法,或者重写了父类的初始化方法,则父类的全部初始化不能被子类调用。
  • 你能够给子类添加和父类相同的初始化方法,但须要加上override修饰。

3.2.二、convenience

  • 在同一个类,使用convenience修饰的初始化方法必须调用一个其余初始化方法。
  • convenience必须最终调用一个指定的初始化方法。
  • 重写父类的convenience修饰的方便初始化方法,不须要加override关键字。

3.2.三、required

  • 子类必须重写父类用required修饰的方法
  • 能够和convenience组合使用

参考资料

NS_UNAVAILABLE 与 NS_DESIGNATED_INITIALIZER

Swift 初始化(Initialization)

Swift-init初始化方法

相关文章
相关标签/搜索