目次
はじめに
本記事はSwiftでよく使う高階関数をまとめた記事です。
関数自体を引数や戻り値として使える関数を高階関数といいます。Swiftではコレクション操作の際に便利な高階関数が用意されいるのでご紹介します。
実行環境
この記事は以下の動作環境で動作確認しています。
- Xcode 11.5
- Swift 5.2.4
準備
実際のプロジェクトではAPIのレスポンスや画面の持つデータなど、structとその配列で使用されることが多いです。
そのため今回は、QiitaのAPIのレスポンスを使って実際に高階関数を使用してみようと思います。
以下のコードで記事を20件取得します。
import Foundation
import UIKit
struct Article: Codable {
struct Tags: Codable {
let name: String
}
struct User: Codable {
let followeesCount: Int
let followersCount: Int
let githubLoginName: String?
let id: String
let itemsCount: Int
let name: String
}
let coediting: Bool
let commentsCount: Int
let createdAt: String
let id: String
let likes_count: Int?
let reactionsCount: Int
let tags: [Tags]
let title: String
let updatedAt: String
let url: String
let user: User
}
let urlStr = "https://qiita.com/api/v2/items?page=1"
var urlRequest = URLRequest(url: URL(string: urlStr)!)
urlRequest.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: urlRequest, completionHandler: { data, response, error in
guard let data = data else { return }
var articles: [Article] = []
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
articles = try decoder.decode([Article].self, from: data)
} catch let e {
print("JSON Decode Error :\(e)")
}
// ここで高階関数を使っていきます。
})
task.resume()
高階関数の例
forEach
forEachは配列の操作後に返り値が必要ない時に使用します。
サンプル
以下は記事のタイトルの数だけラベルを生成してtextをセットする処理です。
値を何かにセットして、返り値は使用しない場面で使います。
articles.forEach {
let label = UILabel()
label.text = $0.title
}
map
mapは配列の操作後に返り値が必要な場合に使用します。
サンプル
配列の要素から特定の値を取り出したり、配列の要素を元に別のデータに変換してまた配列を作りたい時などに利用します。
// userだけの配列を作る
let users = articles.map { $0.user }
// IDとタイトルの辞書の配列を作成する。
let artices = articles.map { article -> [String: String] in
return [article.id: article.title]
}
compactMap
compactMapもmapと同様に返り値が必要な際に利用します。
mapとの違いは返り値がオプショナルを含むかどうかです。
mapの場合はオプショナルな値はそのままオプショナルとして返却されますが、compactMapを使用するとnilを排除した非オプショナルな値となります。
サンプル
変換した値がオプショナルとなるが、nilの場合は排除したい場合などによく使います。
日付の変換やURLへの変換が思いつきます。
// 日付を変換して返す
let createdAtList = articles.compactMap { stringFromDate(string: $0.createdAt) }
// 文字列のurlをURLに変換して返す。
let urlList = articles.compactMap { URL(string: $0.url) }
filter
filterは条件に当てはまる要素のみ抽出したい時に使います。
ブロックでBool値をreturnし、その値がtrueの時は取り出す要素に含めます。
サンプル
// コメントを持っている記事のみ抽出する
let hasCommentArtices = articles.filter { $0.commentsCount > 1 }
filterで取得した結果は配列になりますが、一つだけ抽出したい場合はfirstを使います。
filterした結果にfirstを使っても良いですが、first(where: )を使用すると一回で済むので楽です。
サンプル
let nextDaysFirstArtice = articles.first(where: {
guard let convertedCreatedAt = stringFromDate(string: $0.createdAt) else {
return false
}
return Date() > convertedCreatedAt
})
おわりに
Swiftでよく使う高階関数を紹介しました。
他にもたくさん種類がありますので配列の操作をする時に是非使ってみてください。