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

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

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

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

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

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

1986閲覧

エラーとSwitch文について教えて下さい。

Ytan

総合スコア39

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

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

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2020/03/01 00:21

編集2020/03/01 21:46

前提・実現したいこと

1-7個あるimageを二個のボタンどちらを最初に押すかによってimageの切り替えの増え方を変えたいです。


最初にleftButtonを押した場合、
それからの処理はleftを押すとimageが1.3.5.7と変わり、rightを押すとimageは1-7のように始めにどちらのボタンを押すかにとって、それからの処理の条件を変化させたいです。

最初にrightuttonを押した時はそれからの処理はleftを押すとimageが1-7と変わり、rightを押すとimageは1.3.5.7です。

そして、ansewerNumberが設定してない8になったら画面遷移をしたいです。

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

1 こちらのコードだと交互にボタンを押した場合、どちらも1-7となってしまいます。

2 また7枚目まで行くと8枚目まで行かず画面遷移されずにそれで終わってしまいます。

該当のソースコード

import UIKit class ViewController: UIViewController { //どちらのボタンを押すかで回数を確定させる var answerNumber = 0 override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } @IBOutlet weak var imageView: UIImageView! @IBOutlet weak var Label: UILabel! enum actionTag : Int { case action1 = 1 case action2 = 2 } @IBAction func left(_ sender: Any) { //条件分岐 if let button = sender as? UIButton { if let tag = actionTag(rawValue: button.tag) { switch tag { case .action1: answerNumber = answerNumber * 2 case .action2: answerNumber = answerNumber + 1 default: break } } } //imageの画像を変換させたい //0枚目 if answerNumber == 0 { Label.text = "hazime" imageView.image = UIImage(named:"0") } else if answerNumber == 1 { //1枚目 Label.text = "itibann" imageView.image = UIImage(named:"1") } else if answerNumber == 2 { //2枚目 Label.text = "nibann" imageView.image = UIImage(named:"2") } else if answerNumber == 3 { //3枚目 Label.text = "sannban" imageView.image = UIImage(named:"3") } else if answerNumber == 4 { //4枚目 Label.text = "yonban" imageView.image = UIImage(named:"4") }else if answerNumber == 5 { //5枚目 Label.text = "goban" imageView.image = UIImage(named:"5") } else if answerNumber == 6 { //6枚目 Label.text = "rokuban" imageView.image = UIImage(named:"6") } else if answerNumber == 7 { //7枚目 Label.text = "nanaban" imageView.image = UIImage(named:"7") } answerNumber = answerNumber + 1 ///imageが8に達したら画面遷移 if answerNumber == 8 { answerNumber = 0 performSegue(withIdentifier: "next", sender: nil) } } @IBAction func right(_ sender: Any) { if let button = sender as? UIButton { if let tag = actionTag(rawValue: button.tag) { switch tag { case .action1: answerNumber = answerNumber + 1 case .action2: answerNumber = answerNumber * 2 default: break } } } //imageの画像を変換させたい //0枚目 if answerNumber == 0 { Label.text = "hazime" imageView.image = UIImage(named:"0") } else if answerNumber == 1 { //1枚目 Label.text = "itiban" imageView.image = UIImage(named:"1") } else if answerNumber == 2 { //2枚目 Label.text = "niban" imageView.image = UIImage(named:"2") } else if answerNumber == 3 { //3枚目 Label.text = "sanban" imageView.image = UIImage(named:"3") } else if answerNumber == 4 { //4枚目 Label.text = "yonban" imageView.image = UIImage(named:"4") }else if answerNumber == 5 { //5枚目 Label.text = "goban" imageView.image = UIImage(named:"5") } else if answerNumber == 6 { //6枚目 Label.text = "rokuban" imageView.image = UIImage(named:"6") } else if answerNumber == 7 { //7枚目 Label.text = "nanaban" imageView.image = UIImage(named:"7") } answerNumber = answerNumber + 1 ///imageが8に達したら画面遷移 if answerNumber == 8 { answerNumber = 0 performSegue(withIdentifier: "next", sender: nil) } } }

試したこと
switch文の使い方がまだ上手く分かっていないので、サイトから見様見真似で
if let button = sender as? UIButton {
if let tag = actionTag(rawValue: button.tag) {

switch tag { case .action1: answerNumber = answerNumber + 1 case .action2: answerNumber = answerNumber * 2 default: break } } }

のところを追加しました、こちらを追加する前の処理では、一枚ずつ増えて8で画面遷移がちゃんと行われました。

補足情報(FW/ツールのバージョンなど)
Swift5
xcode 11.3.1

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

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

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

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

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

TsukubaDepot

2020/03/01 02:03 編集

この質問ですが、単に switch 文だけの話ではなく、 1. tag を伴う UI 部品の制御 2. イニシャライザを使った列挙型(enum型)のインスタンスの作成 3. switch文を使った流れの制御 4. オプショナルバインディング(if-let)文 5. as! 演算子によるダウンキャスト(と、ダウンキャストに失敗したときの処理) の5つの理解が必要ですが、どこまで理解されていますか? それによって説明の方法が異なります。 さらに突っ込むと、 > 最初にleftButtonを押した場合、それからの処理はleftを押すとimageが1.3.5.7と変わり、rightを押すとimageは1-7のように始めにどちらのボタンを押すかにとって、それからの処理の条件を変化させたいです。 > 最初にrightuttonを押した時はそれからの処理はleftを押すとimageが1-7と変わり、rightを押すとimageは1.3.5.7です。 この流れを、ご自身でフローチャートに書き起こすことはできますか? 頭の中で想像するだけではなく、具体的に流れとして記述できるか否かという質問です。
Ytan

2020/03/01 21:48

質問の5つの項目ですが、5つとも理解していないと言えます。 その場合だと一回基礎を学んでからの方がよろしいのでしょうか?
TsukubaDepot

2020/03/01 23:26

ソースコード見やすくなりました。ありがとうございます。 ネットや本などからソースコードを引用して自分のコードにしようとすると、やはりSwiftの文法の理解やアルゴリズム、データ構造の理解は避けて通れないと思いますので、合わせて習得されるのがいいと思います。 switch 文へのコメントはあとで書いておきますので(switch文やオプショナルバインディング、enum値なども使わない方法も)、合わせて参考にしてください。
guest

回答1

0

ベストアンサー

switch文そのものは非常にシンプルです。
次のような感じで使います。
playgroundで変数や条件の値を変更しながら実行してみるのがいいと思います。

Swift

1let n = 1 2 3switch n { 4case 1: 5 print("最初のcase") 6case 2: 7 print("2つめのcase") 8default: 9 print("該当なし") 10} 11 12// 範囲演算子も使える 13let s = 68.6 14 15switch s { 16case 80...: 17 print("A") 18case 70..<80: 19 print("B") 20case 60..<70: 21 print("C") 22case ..<60: 23 print("不合格") 24default: 25 print("該当なし") 26}

基本は caseに条件を書き、続く行に処理を書きます。
複数行の処理も可能です。

どの条件にも合わない処理はdefault:以降で行います。

基本的に(例外あり) default:が無い switch文はエラーが出るので、その点は注意が必要です(注意というか、条件漏れがないように配慮してくれる)。

さらにはパターンマッチやlet文を使った代入などもできますが、いまは必要なさそうなので説明は省略します。

switch 文を使わずに実現するには

そもそも実現されたいことについては、switch文を使わなくても、変数を2つ使ってボタンの状態を把握することで実現できると思います。

これであれば if文だけでも実現できます(簡単なswitch文であれば if-elseの組み合わせでも実現できるため)。

ボタンを押すことによる数値の変化については一部不明な点もありますが、概ねこんな感じなんだろうと思います。

Swift

1import UIKit 2 3class ViewController: UIViewController { 4 5 @IBOutlet weak var tokutenLabel: UILabel! 6 7 // 初回のタップが行われたか 8 var isFirstTap = false 9 var isLeftFirst = false 10 var tokuten = 0 11 12 override func viewDidLoad() { 13 super.viewDidLoad() 14 // Do any additional setup after loading the view. 15 tokutenLabel.text = String(tokuten) 16 } 17 18 @IBAction func leftButton(_ sender: Any) { 19 if isFirstTap == false { 20 // 両方とも最初のタップの場合 21 22 // 初回タップを記憶 23 isFirstTap = true 24 // 左側が押されたことを記憶 25 isLeftFirst = true 26 27 // 初回のラベルの値 28 tokuten = 1 29 } else { 30 // 2回目以降のタップの場合 31 if isLeftFirst == true { 32 tokuten += 2 33 } else { 34 tokuten += 1 35 } 36 } 37 38 tokutenLabel.text = String(tokuten) 39 40 // ここにImageの更新やsegueの実行を入れる 41 } 42 43 @IBAction func rightButton(_ sender: Any) { 44 if isFirstTap == false { 45 // 両方とも最初のタップの場合 46 47 // 初回タップを記憶 48 isFirstTap = true 49 // 押されたのは左側では「無い」ので false 50 isLeftFirst = false 51 52 tokuten = 1 53 } else { 54 // 2回目以降のタップの場合 55 if isLeftFirst == true { 56 tokuten += 1 57 } else { 58 tokuten += 2 59 } 60 } 61 62 tokutenLabel.text = String(tokuten) 63 64 // ここにImageの更新やsegueの実行を入れる 65 } 66 67}

あえて冗長に書きました。

なので、同じような処理は関数にすることでもっと簡素化することができますし、変数isLeftFirstをオプショナル型にすれば(変数の値にnil, true, falseの3つの値を持たせることで)、変数isFirstTapも省略することも可能です。

#質問への追記について

質問の5つの項目ですが、5つとも理解していないと言えます。
その場合だと一回基礎を学んでからの方がよろしいのでしょうか?

やはり、基本的な制御文(if-else,for-in, switch-caseなどなど)の存在とそれらの具体的な使い方、変数の使い方については押さえておいた方がいい、というか必須だと思います。

制御文を用いたプログラムの制御とその理解は、別にSwiftに限った話ではなく、あらゆるプログラミング言語の基本となります。

ネットで調べられたことや、teratail でアドバイスを受けたことをうまく活用するためにも必要ですし、今後余計な労力を払わずに開発を進めるためにも必要です。

私が訪ねた5つの質問ですが、

  1. tag を伴う UI 部品の制御
  2. イニシャライザを使った列挙型(enum型)のインスタンスの作成
  3. switch文を使った流れの制御
  4. オプショナルバインディング(if-let)文
  5. as! 演算子によるダウンキャスト(と、ダウンキャストに失敗したときの処理)

このうち3. について最低限必須な知識になりますし、4-5については、Swiftを使ってiOSで動くグラフィカルなアプリを作る上では理解は必須だと思います。

3. については先にも書きましたが、これは基本的な制御文ですから押さえておく必要はあります(if-elseで代用可能ですが、より見通しの良いプログラムを書く上で必須です)。

4. ですが、変数やメソッドが nil か否か、nilでなければどうするかという処理は至るところにありますから、理解必須です。

5. ですが、たとえばセグエ(segue)を使って別のインスタンス(ビュー、あるいは画面)に値を渡す場合などには避けて通れないのかな、と思います。

それ以外にもUI部品に渡されるsenderという変数もAny型で定義されていますが(これは具体的な型にすることができるはずですが)、ここで渡された変数を使う場合にも必要です。

提示していただいたコードの中で

Swift

1  if let button = sender as? UIButton {

こういう行がありますが、まさにこれが型の変換です。

Any型で渡された変数をより具体的な型に変換(キャスト)するには as?演算子もしくはas!演算子を使いますが、それぞれ実行結果が異なるので、理解して使わないと実行時エラーを引き起こしてしまいます。

なかなかやることが多くて大変だったと思いますが、必要に迫られて知識を整理することで、いままで見えてこなかったことが明らかに違った視点で見えてくると思いますのでお勧めします。

投稿2020/03/02 08:43

TsukubaDepot

総合スコア5086

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

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

Ytan

2020/03/03 06:37

とても分かりやすい説明とていねいなご説明ありがとうございます。 やる事が多いですが、やはり基本なので一つずつやっていきたいと思います。 ありがとうございました。
TsukubaDepot

2020/03/03 09:12

どんなに複雑なプログラムも、必ず小さい要素に分解できますから、まずは小さなサンプルをいくつも作り、それを組み合わせるようにするといいと思います。
Ytan

2020/03/06 03:40

switch文を教えてもらったif文に書き換えて思い通りに遷移もされるのですが、Bクラスで戻るButtonをdismissにて行ったのですが、戻ったときに初期状態に戻らなく、始めに押されたボタンを継承したままで、右を最初に押したあと画面遷移して戻ると次に左を押しても左は1個づつしか増えません、初期化をしたい時はどうすればよいのですか?
TsukubaDepot

2020/03/06 06:27

Bクラスに遷移しても、呼び出し元のクラスで使っている変数は初期化されませんから(生きたまま、という表現が適切かわかりませんが、呼び出し元のクラスは生き続けています)、Bクラスをdismissしたあと呼び出し元クラスに戻ったときには、改めて変数を自分でリセットする必要があります。 たとえば、viewが表示される「前」に呼び出されるメソッドに viewWillAppear がありますが、その内部でこんな感じでフラグなどをリセットする方法があるとおもいます。 override func viewWillAppear(_ animated: Bool) { // 親クラスの同じ名前のメソッドを呼び出す super.viewWillAppear(animated) isFirstTap = false isLeftFirst = false tokuten = 0 tokutenLabel.text = String(tokuten) } viewDidAppear でも同じようなことはできますが、こちらは表示された後に呼び出されるので、一瞬古い表示のままのラベルが残ってしまいます。試してみるといいと思いますよ。
Ytan

2020/03/06 20:21

自分もviewWillAppearかと思っていたのですがイマイチ実証の仕方がわかりませんでしたが、どうやらPresentationがFullscreanになっていない事が原因でした。試した所うまく動作しました! 本当に一から何まで教えてくださりありがとうございます。 色々新しいことも知る事ができました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問