本篇分兩部分:
一、extension在 Swift 中的使用
二、Swift 中的 fatalError
一、extension在 Swift 中的使用
在 swift 中我們可以通過 extension 來輸出做格式化等操作
通常情況下,當我們在開發過程中需要打印某些對象中的信息時,我們會編寫如下代碼:
struct Meeting { var date: NSDate var place: String var attendeeName: String } let meeting = Meeting(date: NSDate(timeIntervalSinceNow: 86400), place: "會議室B", attendeeName: "小明") print(meeting)
print("與 \(meeting.date) 在 \(meeting.place) 與 \(meeting.attendeeName) 進行會議")
輸出結果:
這種開發方式在 Swift 中可以算得上是非常傳統的代碼了,如果我們需要輸出其他對象的一些信息時,會不斷手動實現上面的代碼,如果過於頻繁會大大降低開發效率,所以,這里我們可以利用 extension 特性來進行優化。
extension Meeting: CustomStringConvertible { var description: String { return "與 \(meeting.date) 在 \(meeting.place) 與 \(meeting.attendeeName) 進行會議" } } print(meeting)
輸出結果:
二、Swift 中的 fatalError
let array: NSArray = [1,2,3]
上面的數組長度為3,如果我們在開發過程中由於某些原因,在使用上面的數組時寫成了 array[100] 就會報數組越界錯誤,程序崩潰。
在 OC 中數組越界輸出的錯誤信息為:*** Terminating app due to uncaught exception 'NSRangeException',reason: '*** -[__NSArrayI objectAtIndex:]:index 100 beyond bounds [0 .. 2]'
在 Swift 中為 fatal error: Array index out of range
在調試時我們可以用斷言來排除類似這樣的問題,但是斷言只會在 Debug 環境中有效,而在 Release 編譯中所以變得斷言都將被禁用。所以我們會考慮以產生致命錯誤(fatalError)的方式來種植程序。
enum MyEnum { case Value1,Value2,Value3 } func check(someValue: MyEnum) -> String { switch someValue { case .Value1: return "OK" case .Value2: return "Maybe OK" default: // 這個分支沒有返回 String,也能編譯通過 fatalError("Should not show!") // return "Should not show!" } }
let a = check(.Value3)
這時如果我們傳入的參數不屬於指定范圍,這里就會報錯
當我們在開發過程中,遇到不想讓別人調用而又不得不將其暴漏出來的方法時,一個最常見並且合理的需求就是”抽象類型或者抽象函數“。在很多語言中都有這樣的特性:父類定義了某個方法,但是自己並不給出具體實現,而是要求繼承他的子類去實現這個方法,而在 OC 和 Swift 中都沒有直接的這樣的抽象函數語法支持。在面對這種情況時,為了確保子類實現這些方法,而父類中的方法不被錯誤的調用,我們就可以利用 fatalError 來在父類中強制拋出錯誤,以保證使用這些代碼的開發者留意到他們必須在自己的子類中實現相關方法。
class MyClass { func methodMustBeImplementedInSubclass() { fatalError("這個方法必須在子類中被重寫") } } class YourClass: MyClass { override func methodMustBeImplementedInSubclass() { print("YourClass 實現了該方法") } } class TheirClass: MyClass { func someOtherMethod() { } // override func methodMustBeImplementedInSubclass() { // print("TheirClass 實現了該方法") // } } YourClass().methodMustBeImplementedInSubclass()
TheirClass().methodMustBeImplementedInSubclass()
這個方法必須在子類中被重寫,否則會編譯報錯
不僅僅是對於類似抽象函數的使用中可以選擇 fatalError,對於其他一切我們不希望別人隨意調用,但是又不得不去實現的方法,我們都應該使用 fatalError 來避免任何可能的誤會。比如父類標明了某個 init 方法是 required 的,但是你的子類永遠不會使用這個方法來初始化時,就可以采用類似的方法,被廣泛使用(以及被廣泛討厭的)init(coder: NSCoder)就是一個例子。在子類中我們往往會寫:
required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") }
來避免編譯錯誤。