iOS版 Kyash Widgetのエラーハンドリング事例

はじめに

はじめまして。KyashのモバイルチームでiOSアプリの開発を担当している emoto です。

今回は、KyashアプリのWidgetでどのようにエラーをハンドリングしているのかを紹介します。私自身、実際に開発してみてデータ取得時にエラーが発生した場合にどうやってViewに伝えるのか悩んだのでこの記事が誰かの助けになると嬉しいです。

KyashアプリのWidgetではアプリを開かずに残高とポイントが確認できるので是非使ってみてください!

データ取得の成功と失敗をどう区別するのか

Widgetで表示するデータを取得する際に呼ばれるメソッドは下記のようになっています。

func getTimeline(
    for configuration: ConfigurationIntent, 
    in context: Context, 
    completion: @escaping (Timeline<Entry>) -> ()
)

developer.apple.com

Viewにデータを渡す時は引数で渡される completion() に取得したデータをTimelineでwrapして渡して、呼び出します。

completion( Timeline(entries: entries, policy: .atEnd) )

Timeline でwrapするデータは TimelineEntry に準拠する必要があるので、

struct ResponseEntry: TimelineEntry {}

struct ErrorEntry: TimelineEntry {}

のように定義して、API通信処理の結果でswitch文で呼び分ければ良さそうです。

func getTimeline(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {

    ...

    // API通信処理の結果
    switch result {
        case .success(let entries):
            let timeline = Timeline(entries: entries.map { ResponseEntry }, policy: .atEnd)
            completion(timeline)
        case .failure(let error):
            let timeline = Timeline(entries:[ErrorEntry(error)], policy: .atEnd)
            completion(timeline)
    }
}

しかし、これだと上手く行きません...

注意してcompletion()の定義を見てみると

completion: @escaping (Timeline<Entry>) -> ()

となっていて渡せる TimelineEntry は1つの型になっています。なので、API通信処理の結果によって ResponseEntry or ErrorEntry を渡すことができません。

そこでKyashではどう実装しているかというと、Widgetで表示するデータとAPI通信処理の結果を保持する TimelineEntry を定義しています。

struct ResponseEntry: TimelineEntry {
    let date: Date
    let result: Result
}

enum Result {
    case loaded(data: ResponseData)
    case error(message: String)
}

struct ResponseData {
    let hogehoge: String
}

enumで定義した Result は馴染みがある形じゃないかなと思います。

View側で参照する時は下記のように実装します。

import SwiftUI
import WidgetKit

struct SampleEntryView: View {
    let entry: ResponseEntry

    var body: some View {
        switch entry.result {
        case let .loaded(data):
            LoadedView(data: data)
        case let .error(message):
            ErrorView(message: message)
        }
    }
}

自分だったらこう実装する!というコメント大歓迎なので、コメントいただけると嬉しいです。

最後に

Kyashでは一緒に働いてくださるエンジニアを募集中です。 Fintechにご興味のある方是非是非選考のご応募待っております。

herp.careers

Kyashについてもう少し知りたい方はこちらからもどうぞ!

Productブログ:https://blog.kyash.co/
Kyash People:https://note.com/kyash_co/
Podcasthttps://open.spotify.com/show/36D8klfwbNF3ger0blVXH3
採用リポジトリ : https://github.com/Kyash/recruitment