把Swift中的Error
移植到Objective-C躺屁,相對而言倒是個簡單很多的事情肯夏。Swift會根據(jù)enum
的名字自動生成默認的error domain,并從0開始楼咳,為每一個enum
中的case
設(shè)置error code熄捍。
為了看到映射的結(jié)果,首先母怜,我們得把上一節(jié)中的struct Car
改成一個NSObject
的派生類余耽,并給它添加一個memberwise init方法:
class Car: NSObject {
var fuelInLitre: Double
init(fuelInLitre: Double) {
self.fuelInLitre = fuelInLitre
}
// ...
}
然后,在Sensor.m中苹熏,我們先包含Swift類在Objective-C中的頭文件:
#import "SwiftErrorsInOC-Swift.h"
就可以在Objective-C中使用class Car
了碟贾。然后,我們定義一個全局函數(shù)startACar()
:
// In Sensor.m
NSObject* startACar() {
Car *car = [[Car alloc] initWithFuel:5];
NSError *err = nil;
[car startAndReturnError: &err];
if (err != nil) {
NSLog(@"Error code: %ld", (long)err.code);
NSLog(@"Error domain: %@", err.domain);
return nil;
}
return car;
}
在上面的代碼里可以看到轨域,由于Swift中的Car.start()
是一個throws
方法袱耽,在OC里,它會被添加一個AndReturnError
后綴干发,并接受一個NSError **
類型的參數(shù)朱巨。然后,當(dāng)err
不為nil
時枉长,我們向控制臺打印了start
拋出的錯誤映射到OC的結(jié)果冀续。
由于car
對象的fuel
只有5,所以這個調(diào)用是一定會產(chǎn)生NSError
的必峰。為了在Swift中調(diào)用這個方法洪唐,我們在Sensor.h
中添加下面的聲明:
// In Sensor.h
NSObject* startACar();
然后,在main.swift里吼蚁,我們直接調(diào)用startACar
凭需,就能在控制臺看到類似這樣的結(jié)果:
在這里,自動生成的NSError
對象的code是0,domain是“項目名.Swift中enum的名字”粒蜈。當(dāng)然顺献,這只是最基本的映射。在Swift 3里薪伏,除了Error
之外滚澜,還添加了一些新的protocol
粗仓,幫助我們進一步定制自動生成的NSError
對象的屬性嫁怀。
LocalizedError
第一個要介紹的,是LocalizedError
借浊,它的定義是這樣的:
protocol LocalizedError : Error {
/// A localized message describing what error occurred.
var errorDescription: String? { get }
/// A localized message describing the reason for the failure.
var failureReason: String? { get }
/// A localized message describing how one might recover from the failure.
var recoverySuggestion: String? { get }
/// A localized message providing "help" text if the user requests help.
var helpAnchor: String? { get }
}
并且塘淑,Swift為LocalizedError
中的每一個屬性都提供了默認值nil
,因此蚂斤,你可以只定義自己需要的部分就好了存捺。例如,對于我們的CarError
來說曙蒸,可以把它改成這樣:
enum CarError: LocalizedError {
case outOfFuel
}
然后捌治,通過extension
給它添加額外信息:
extension CarError: LocalizedError {
var recoverySuggestion: String? {
return "Switch to e-power mode"
}
}
這樣,在OC的startACar
實現(xiàn)里纽窟,我們就可以通過訪問NSError
的localizedRecoverySuggestion
屬性來讀取恢復(fù)建議了:
NSObject* startACar() {
// ...
if (err != nil) {
// ...
NSLog(@"Recovery suggestion: %@",
err.localizedRecoverySuggestion);
return nil;
}
// ...
}
CustomNSError
另外一個加入到Swift的protocol
是CustomNSError
肖油,我們可以通過它自定義NSError
中的code / domain / userInfo。
extension CarError: CustomNSError {
static let errorDomain = "CarErrorDomain"
var errorCode: Int {
switch self {
case .outOfFuel:
return -100
}
}
var errorUserInfo: [String: Any] {
switch self {
case .outOfFuel:
return [
"LocalizedDescription":
"U r running out of fuel"
]
}
}
}
盡管在SE-0112的約定里臂港,errorDomain
是一個computed property森枪,但至少在XCode 8.2.1中,它只能定義成一個type property审孽。不過想來也合理县袱,一個NSError
對象只需要一個error code就可以了,我們也沒什么計算它的必要佑力。
接下來式散,把startACar
的定義改成這樣:
NSObject* startACar() {
// ...
if (err != nil) {
NSLog(@"Error domain: %@", err.domain);
NSLog(@"Error code: %ld", (long)err.code);
NSLog(@"Error userInfo: %@", err.userInfo);
}
// ...
}
我們就能在控制臺看到自定義的結(jié)果了: