しおメモ

雑多な技術系ブログです。ニッチな内容が多いです。

SwiftでRustのようなResult型を実装する

Swiftで従来のthrow~catchでは書きづらい場面も多々あるので、
RustのResult型を参考にした、エラーハンドルを取り入れてみました。

やること

SwiftでRustのResult型のような、直和型の返り値を使ったエラーハンドルを実現する。

std::result::Result - Rust

実装

enumを使って直和型であることを表現します。
Genericsとassociated valueで、結果(型T)かエラー(型E)のどちらかの値を持つ状態を表現します。

case

Rustに倣って、okerrorの2つのcaseを持ちます。

enum Result<T, E> {
    case ok(T)
    case error(E)
}

switch文で、okの場合とerrorの場合の処理を記述することができます。

メソッド

ok, errorの場合のみ処理を書きたい時のために、Optionalで返すメソッドを用意します。

func ok() -> T? {
    switch self {
    case .ok(let result):
        return result
    case .error:
        return nil
    }
}

func error() -> E? {
    switch self {
    case .ok:
        return nil
    case .error(let error):
        return error
    }
}

その他

例えば、mapなどの実装はこのようになります。

func map<U>(_ transform: ((T) -> U)) -> Result<U, E> {
    switch self {
    case .ok(let result):
        return .ok(transform(result)) as Result<U, E>
    case .error(let error):
        return .error(error) as Result<U, E>
    }
}

使い方

switchで使う

typealias Res = Result<Int, String>
let someResult: Res = .ok(1)

switch someResult {
case .ok(let result):
    print(result)
case .error(let error):
    print(error)
}

Optionalで使う

if let result = someResult.ok() {
    print(result)
}

サンプル

ここにあります。

github.com

Obj-Cライブラリ由来のNSExceptionのSwiftでのハンドリング

ずばりこれ。
NSSetUncaughtExceptionHandler(_:) - Foundation | Apple Developer Documentation

swiftのcatchで拾えないものもこちらでハンドルできる。
AppDelegate等に入れておく。

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.
    NSSetUncaughtExceptionHandler { exception in
        print(exception)
        fatalError() // 適当な処理の後落とす
    }
    return true
}

ただ処理を継続しようとしても落ちるので、fatalError等できちんと落とす。

iOS Simulatorにディスクイメージをマウント

hdiutilからマウントできました。Xcode 10👌です。

ディスクイメージ作成

iOSのシステムが数百MB使用するので、その分は最低限起動に必要です。

# APFS
hdiutil create -size 1g -fs APFS /tmp/ios.dmg
# HFS+
hdiutil create -size 1g -fs HFS+ /tmp/ios.dmg

Simulatorのデバイスにマウント

新しくシミュレータを用意しておいたほうが良いです。

f:id:scior:20181010220514p:plain

マウント先のデバイスのパスは、~/Library/Developer/CoreSimulator/Devices/[Device Identifier]です。

cd ~/Library/Developer/CoreSimulator/Devices/CB63F64D-xxxx
hdiutil attach /tmp/ios.dmg -mountpoint .

起動

起動済みのシミュレーターの場合、XcodeからRunすると1回怒られますが、

f:id:scior:20181011002755p:plain

もう一回Runすると起動できます。

f:id:scior:20181011005612p:plain