Swift开发第二篇——extension及fatalError
本篇分两部分:
一、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") }
来避免编译错误。