質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Q&A

解決済

2回答

1996閲覧

enumを用いたswitchの取得

Narikura

総合スコア6

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

0グッド

0クリップ

投稿2020/10/24 06:35

前提・実現したいこと

アラート専用のファイルを作成し、viewControllerで出力する。
アラートファイルでは可読性をあげるためにenumを使ってSwitch文の分岐をIntではなくStringで表示させ、その場に応じて異なったアラートを表示させる。
今回の場合、アラートのtitleとmessageを2種類用意し、2箇所で使用する予定。

発生している問題・エラーメッセージ

色々試し、様々なエラーが出ていましたが、今はenumがviewControllerで取得できないのが1番の原因かと思われます。

Cannot find 'ErrorType' in scope

該当のソースコード

Alert

1import Foundation 2import UIKit 3 4class Alert: UIAlertController { 5 6 static func show(title: String, message: String, viewController: UIViewController) { 7 enum ErrorType { 8 case failedLoadUrl 9 case failedFetchAPI 10 11 func title() -> String { 12 switch self { 13 case .failedLoadUrl: 14 return "Webページの取得に失敗しました" 15 case .failedFetchAPI: 16 return "タイトルの取得に失敗しました" 17 } 18 } 19 20 func message() -> String { 21 switch self { 22 case .failedLoadUrl: 23 return "もう一度やり直してください" 24 case .failedFetchAPI: 25 return "アプリを再起動し、もう一度やり直してください" 26 } 27 } 28 } 29 } 30} 31

ViewController

1class ViewController: UIViewController { 2 3 Alert.show(title: ErrorType.failedLoadUrl.title(), message: .failedLoadUrl.message(), viewController: self) 4 5} 6

試したこと

Alert.showのtitle, messageの欄にenumで設定した2つの文字列を色々挿入してみましたがうまくいきませんでした。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

期待されている文脈で使うのであれば、Alert クラスのトップレベルで enum を定義してあげるのがいいかと思います。

Swift

1import UIKit 2 3class Alert: UIAlertController { 4 enum ErrorType { 5 case failedLoadUrl 6 case failedFetchAPI 7 8 func title() -> String { 9 switch self { 10 case .failedLoadUrl: 11 return "Webページの取得に失敗しました" 12 case .failedFetchAPI: 13 return "タイトルの取得に失敗しました" 14 } 15 } 16 17 func message() -> String { 18 switch self { 19 case .failedLoadUrl: 20 return "もう一度やり直してください" 21 case .failedFetchAPI: 22 return "アプリを再起動し、もう一度やり直してください" 23 } 24 } 25 } 26 27 static func show(title: ErrorType, message: ErrorType, viewController: UIViewController) { 28 let titleString = title.title() 29 let messageString = message.message() 30 31 // あとは適切に扱う 32 print("Title:", titleString) 33 print("Message:", messageString) 34 } 35}

show()の第一引数、第二引数の型は、ご自身で作られた ErrorType 型になります。このようにしておけば、

Swift

1 Alert.show(title: .failedLoadUrl, message: .failedLoadUrl, viewController: self)

のような感じで呼び出せますし、Xcode は引数の型をみて適切な候補を推論できるようになりますので、引数に指定できる enum の値を限定(failedLoadUrl もしくは failedFetchAPI)することが可能となります。

元々のコードで呼び出されていた

Swift

1 Alert.show(title: ErrorType.failedLoadUrl.title(), message: .failedLoadUrl.message(), viewController: self)

だと、毎回打ち込む本人が ErrorType という型を覚えておく必要があり、またtitle()などのプロパティまで指定しなければいけないため、かえって扱いが面倒になってしまいます。

これらのことを考えると、titlemessage の両方を引数として与える必要があるのかも考え直すことができるかと思います。titlemessage の組み合わせが限定できるのであれば、むしろ

Swift

1 static func show(reason: ErrorType, viewController: UIViewController) { 2 let titleString = reason.title() 3 let messageString = reason.message() 4 5 // あとは適切に扱う 6 print("Title:", titleString) 7 print("Message:", messageString) 8 }

のような感じで、呼び出しに指定する値は「エラーの原因」ひとつにしておいたほうが、今後の拡張性は高くなりそうな気がします。

投稿2020/10/24 10:03

TsukubaDepot

総合スコア5086

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TsukubaDepot

2020/10/24 10:06

ちなみに、エラーの根本的な原因は、miyabi_takatsukさんご指摘のように、スコープ外から参照していることが原因です。 Xcodeの場合、スコープから見えない型は自動補完が効かないようになっています。したがって、 ErrorType. まで打ち込んでも tab 補完ができないのであれば、それは宣言方法が間違っていると疑った方がいいかと思います。
TsukubaDepot

2020/10/24 10:29

ちなみに、show というメソッドはベースクラスの UIAlertController がすでにメソッド名として使っていますので、違う名前にした方が紛らわしくなくて良いかと思います。
miyabi_takatsuk

2020/10/24 11:05

しまった、スーパークラスにあったメソッドでしたか・・・。
TsukubaDepot

2020/10/24 11:18

正確には UIAlertController ではなくて UIViewController でした...
Narikura

2020/10/24 16:17 編集

ご回答ありがとうございます。メソッド名につきましてもベースクラスのメソッド名として使われていないものを使用するよう心がけます(今回のshowはUIViewControllerのようですが)。これまでも質問に答えていただきありがとうございます。とても助かっております。
Narikura

2020/10/24 16:08 編集

(誤入力)
guest

0

ベストアンサー

エラーの通りです。
そのスコープでは、ErrorTypeを使用することはできません。
なぜなら、
Alertクラスのメソッド内で宣言している列挙型なのに、
他のクラスである、
ViewControllerから呼び出すことはできるわけがないからです。
ErrorType列挙型を他のクラスなどで使うならば、
グローバルで定義・宣言しましょう。

コメントに対して

使用の例示を出します。

swift

1import Foundation 2import UIKit 3 4// ここで定義 5enum ErrorType { 6 case failedLoadUrl 7 case failedFetchAPI 8 9 func title() -> String { 10 switch self { 11 case .failedLoadUrl: 12 return "Webページの取得に失敗しました" 13 case .failedFetchAPI: 14 return "タイトルの取得に失敗しました" 15 } 16 } 17 18 func message() -> String { 19 switch self { 20 case .failedLoadUrl: 21 return "もう一度やり直してください" 22 case .failedFetchAPI: 23 return "アプリを再起動し、もう一度やり直してください" 24 } 25 } 26} 27 28class Alert: UIAlertController { 29 // 引数では、ErrorTypeを入れさせる 30 static func show(errorType: ErrorType, viewController: UIViewController) { 31 // 処理では、errorType.title()、errorType.message()で、各文字列を取得できる 32 } 33}

swift

1class ViewController: UIViewController { 2 // メソッドの引数で、ErroType自体を入れるので、ここではString文字列を入れる必要はない 3 Alert.show(errorType: .failedLoadUrl, viewController: self) 4}

投稿2020/10/24 07:45

編集2020/10/24 10:03
miyabi_takatsuk

総合スコア9555

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Narikura

2020/10/24 08:10

ご回答ありがとうございます。enumのグローバル定義の仕方がわかりません。enumにstaticを付けてみましたがエラーが出てしまいました。extensionを利用するのでしょうか。
miyabi_takatsuk

2020/10/24 08:27 編集

class Alert: UIAlertController { の前行に配置・展開し宣言します。 つまり、全てのコードで参照できる位置で宣言します。 というか通常は、 列挙型は、どこからも参照できるようにした方が、処理を活かせるので、グローバルスコープないし、staticなメンバとして配置することが圧倒的に多いですので、 むしろ、クラスメソッド内で列挙型を宣言しているのは初めて見ました。
Narikura

2020/10/24 08:34

ありがとうございます。私の実力が及ばないもので、そうするとSwitchのcaseの部分でenumの要素二つがno member になってしまうのですが、、 また勉強始めなので初めて知りました。助言ありがとうございます。
Narikura

2020/10/24 08:42 編集

class内部のenumは残したままclassの前にも同じコードを記述することでいいのでしょうか。また、そうした際のアラートの呼び出し文はどのように記述するべきなのでしょうか。
miyabi_takatsuk

2020/10/24 09:32

その、アラートの呼び出し文の記載がないので、なんとも言えません。
Narikura

2020/10/24 15:40 編集

コード例を追加していただきありがとうございます。全てのクラスでクラスで参照できるようグローバルでの記述をこれから必要に応じて利用していきます。ありがとうございます。
miyabi_takatsuk

2020/10/24 16:02

解決したなら、BAを選出して、質問を閉じましょう。
Narikura

2020/10/24 16:09 編集

let alert = UIAlertController(title: ErrorType, message: ErrorType, preferredStyle: .alert) viewController.present(alert, animated: true, completion: nil) let actionCancel = UIAlertAction(title: "OK", style: .cancel) { action in print("Pushed CANCEL!") } alert.addAction(actionCancel) ちなみにですが上記のように定義しました。しかしlet alertで定義したアラートのtitleとmessageにenumのErrorTypeを使うとエラー出るのですが使えないのですか? 質問を閉じた後ですので回答する必要はございませんがもしよろしければお願いいたします。
miyabi_takatsuk

2020/10/24 16:52

使えません。 UIAlertContllerのinitの引数のtitleは、 String型しか受け付けません。 ErrorType型は入れることはできません。 型についてと、 初期化メソッド(インスタンスを生成する時に実行されるinitメソッドのこと)についてしっかり学習して下さい。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問