検索キーを用いてgithubAPIを叩き、リポジトリのデータを取得するメソッドの中でエラー処理を書いたのでメモとして記録します。
searchBarに入力した検索ワードからリポジトリを検索してTableViewに表示し、検索を押してエラーが出た際に内容をUIAlertControllerで表示するシンプルなアプリです。
こんな感じ↓
#環境
・macOS Big Sur バージョン11.2.3
・XCode 12.4
・Swift5.3.2
・Alamofire5.4.1 + Codableを使用
#1. エラーを定義する
enum APIError: Error{
case searchWordEmpty
case invalidURL
case networkError
case unknown
var title: String{
switch self{
case .networkError:
return "ネットワークエラー"
case .unknown:
return "不明なエラー"
default:
return "検索エラー"
}
}
var description: String{
switch self{
case .searchWordEmpty:
return "検索ワードを入力してください。"
case .invalidURL:
return "別の検索ワードを試してください。検索ワードには半角英数字のみお使いいただけます。"
case .networkError:
return "接続環境の良いところでもう一度お試しください。"
case .unknown:
return "不明なエラーです。"
}
}
func showAlert(from: UIViewController){
UIAlertController.showAPIErrorAlert(error: self, from)
}
}
ユーザーに分かりやすいように4種類のエラーに分けました。
ユーザー側で修正不可能なエラーは全て不明なエラーとして表示されます。
#2. UIAlertControllerの拡張機能を作る
extension UIAlertController{
static func showAPIErrorAlert(error: APIError, _ viewController: UIViewController){
let title = error.title
let message = error.description
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let action = UIAlertAction(title: "OK", style: .default) { (action) in
alert.dismiss(animated: true, completion: nil)
}
alert.addAction(action)
viewController.present(alert, animated: true, completion: nil)
}
}
titleに先程定義したエラーのタイトル、messageにエラーの詳細(description)を表示させ、OKを押したら閉じるアラートを作成し表示します。
拡張機能+staticでどこでも簡単に呼び出せるようにしました。
#3. API通信を行うメソッドでエラーを取得する
func getRepositoryDataOf(_ searchWord:String, completion:@escaping(Result<(),APIError>)->Void){
guard let url = URL(string: "https://api.github.com/search/repositories?q=\(searchWord)")
else { return completion(.failure(.invalidURL)) } //①
AF.request(url, method: .get, parameters: nil, encoding: JSONEncoding.default).responseJSON { (response) in
do{
guard let data = response.data
else { throw APIError.networkError } //②
let result = try JSONDecoder().decode(Repository.self, from: data)
let tableViewDatasource = TableViewDataSource.shared
tableViewDatasource.repositories = result
DispatchQueue.main.async {
completion(.success(()))
}
}catch{
if error as? APIError == APIError.networkError{
completion(.failure(.networkError)) //②
}else{
completion(.failure(.unknown)) //③
}
print(error)
}
}
}
Result型を用いてcompletionでエラーを渡します。
successの時のデータはシングルトンに格納しているため値渡しは行っていません。
①guard letを使ってエラーを返します
②guard letでthrowしたエラーをdo catch構文、completionを使い渡しています。
③上記2つ以外のAPI通信時に起こるエラーは全てunknownとして渡します
#4. ViewControllerでアラートを表示する
func getRepositoryData(searchWord: String){
GithubAPI.getRepositoryDataOf(searchWord){ [unowned self] (result) in
switch result{
case .success(()):
tableView.reloadData()
case .failure(let error):
error.showAlert(from: self)
}
}
}
//searchBarDelegateメソッド
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
guard let searchWord = searchBar.text,
!searchWord.isEmpty
//検索ワードが空の時のエラー
else { return UIAlertController.showAPIErrorAlert(error: .searchWordEmpty, self) }
getRepositoryData(searchWord: searchWord)
}
API通信を行ってcompletionで受け取ったエラーごとにalertを作成し表示しています。
検索ワードが空の時はAPI通信を行う前にguard letを用いてエラーを表示しています。
#5. 終わりに
API通信時のエラーはこれで網羅できたのではないでしょうか。
修正したほうが良い点があればコメントください!