ジェネリクスについて
最初のうち苦労してたのを思い出して書こうと思いました。
目次
- 用語の定義
- 基本形
- 実装例
用語の定義
ジェネリクスとは、型をパラメータ(引数)として受け取ることで汎用的なプログラムを記述するための機能
基本形
func 関数名<型引数>(引数名: 型引数) -> 戻り値の型 {
呼び出し時の実行文
}
例えば
普通の引数だと
func add(a: Int, b: Int) -> Int {
return a + b
}
let intSum = add(a: 5, b: 10) // Int型
let doubleSum = add(a: 5.5, b: 10.2) // エラー: 引数の型が一致しない
型が固定されていてこの場合doubleSum
はエラーになる。
func add<T: Numeric>(a: T, b: T) -> T {
return a + b
}
let intSum = add(a: 5, b: 10) // Int型
let doubleSum = add(a: 5.5, b: 10.2) // Double型
異なる型に対応可能(上の例だとInt型,Double型)
色々な型で使えるというのが最初に書いた「汎用的なプログラム」の理由です。
実装例
func fetch<T: Requestable>(
_ request: T,
// 成功時の処理
success: @escaping ((T.Response) -> Void),
// 失敗時の処理
error: @escaping ((_ status: APIError.Status) -> Void)) {
currentRequest = AF.request(request)
.validate()
.response { [weak self] response in
// 略
switch response.result {
case .success:
do {
// デコード処理
} catch {
errorHandler(.clientError(category: .decodeError))
}
case .failure(let error):
// エラーの処理
}
}
}
このようにAPIを呼び出す関数があるとします。
引数にTという型を指定しています。
例えば別のファイルや構造体などを設定して、fetch()
メソッドを呼び出す時に引数に設定した型を渡せば実行できます。
例)
let req: LoginApiRequest = LoginApiRequest(userId: userId,
password: password,
instanceToken: instanceToken)
repository.api.fetch(req,
successHandler: { response in
handler(.success(response))
},
errorHandler: {
handler(.failure($0))
})
// ログイン
struct LoginApiRequest {
// ログインAPIリクエストのメソッド・パス・ヘッダー・ボディを設定するコード
let userId: String
let password: String
let instanceToken: String
init(userId: String, password: String, instanceToken: String) {
self.userId = userId
self.password = password
self.instanceToken = instanceToken
}
}
これにより、複数のAPI通信をfetch()
関数だけで行うことができます。