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初始化方法

相關文章
相關標籤/搜索