ViewControllerから別のファイルにAlert表示のメソッドを切り出す際の問題点
複数箇所で同じアラート文を複数の画面で使用するため、ViewControllerから別のファイルにAlert文を切り出そうとしたら、下記のようなエラーが起こりました!
AlertMaker.swift
struct AlertMaker {
func showAPIErrorAlert() {
let alert = UIAlertController(title: "エラー", message: "通信に失敗しました。", preferredStyle: .alert)
let retryAction = UIAlertAction(title: "リトライ", style: .default, handler: {(action) -> Void in
print("OK")
})
let cancelAction = UIAlertAction(title: "キャンセル", style: .default, handler: {(action) -> Void in
print("キャンセル")
})
alert.addAction(retryAction)
alert.addAction(cancelAction)
//🟥 エラー:Cannot find 'present' in scope
present(alert, animated: true, completion: nil)
}
}
なぜ上記のように🟥Cannot find 'present' in scopeというエラーが起こったのか?
func present(
_ viewControllerToPresent: UIViewController,
animated flag: Bool,
completion: (() -> Void)? = nil
)
presentメソッドはclassであるUIViewControllerのメソッドであるため、UIViewController内でしか使用できません。
解決方法:Alert表示のメソッドを切り出す!
AlertMaker.swift
struct AlertMaker {
func showAPIErrorAlert(didTapRetry: @escaping () -> Void) -> UIAlertController {
let alert = UIAlertController(title: "エラー", message: "通信に失敗しました。", preferredStyle: .alert)
let action = UIAlertAction(title: "リトライ", style: .default, handler: {(action) -> Void in
didTapRetry()
})
alert.addAction(action)
return alert
}
}
先ほど見たようにpresentメソッドはUIViewControllerで使用する必要があるため、AlertMakerファイルの戻り値として、UIAlertControllerを戻すようにした。
okyoViewController.swift
class TokyoViewController: UIViewController {
private let latitude = "35.689753"
private let longitude = "139.691731"
let apiClient = APIClient()
let alertMaker = AlertMaker()
@IBOutlet weak var weatherLabel: UILabel!
@IBOutlet weak var prefectureLabel: UILabel!
@IBAction func tappedTokyo(_ sender: UIButton) {
showWetherView()
}
func showWetherView() {
apiClient.getWeatherFromAPI(
latitude: latitude,
longitude: longitude,
success: { description, cityName in
DispatchQueue.main.async {
self.weatherLabel.text = description
self.prefectureLabel.text = cityName
}
},
failure: {
DispatchQueue.main.async {
//🟩UIAlertControllerの戻り値を受け取る!
let alert = self.alertMaker.showAPIErrorAlert {
self.showWetherView()
}
self.present(alert, animated: true, completion: nil)
}
}
)
}
}
UIViewController側で、AlertMakerファイルから🟩UIAlertControllerの戻り値を受け取りalert定数に代入し、presentメソッドのみをUIViewController側で使用することができました!
参考文献