@(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
修飾的方法