🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

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回答

1472閲覧

[Swift5]4択クイズアプリでCSVを用いて復習機能を実装したいです。

kenta2511290621

総合スコア4

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

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クリップ

投稿2019/10/17 22:44

前提

初心者です。
復習機能付きの4択英単語クイズアプリを作っています。CSVから問題や選択肢を呼び出しています。
以下にCSVの一部を例として抜粋します。

verify,2,速度,検証する,作動する,とても,0
common,4,約束,比較,顧問,一般,0

イメージ説明

###実現したいこと

以下の①か②が発生したときに、CSVの各列の最後の値が0から1に変わり、
値が1の問題については、別のストーリーボード上で復習できるようにしたいです。
お気に入り登録のようなイメージになります。

①誤答したとき
②画面右上の星の画像をタップしたとき

CSVの該当列の最後の値は1に変わると、右上の星は"色付きの星"に変わります。
その状態で、正解する or 星をもう1回タップすると値は0となり、
"色なしの星"に戻ります。

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

星をタップすると画像は切り替わりますが、
「次の問題」、「前の問題」に移動してしまうと、移動前の問題に戻ったときに、
星の画像が切り替わっておらず、初期状態となってしまいます。
各問題で、CSVの値が変更されていないか、変更されても毎回保存されていないような状況です。

該当のソースコード

Swift5,Xcode 11.0

import UIKit class QuizViewController: UIViewController { @IBOutlet weak var quizNumberLabel: UILabel! @IBOutlet weak var uiButton1: UIButton! @IBOutlet weak var uiButton2: UIButton! @IBOutlet weak var uiButton3: UIButton! @IBOutlet weak var uiButton4: UIButton! @IBOutlet weak var quizQuestionLabel: UILabel! @IBOutlet var star: UIButton! // UIImage のインスタンスを設定 let image0:UIImage = UIImage(named:"Off_Star")! let image1:UIImage = UIImage(named:"On_Star")! @IBOutlet weak var answerImage: UIImageView! var csvArray = [String]() var questionArray = [String]() var questionCount = 0 var correctCount = 0 let total = 200 let waitQuestion = 0.8 var userPath:String! var count = 0 override func viewDidLoad() { super.viewDidLoad() csvArray = loadCSV(filename: "Eitango") answerImage.isHidden = true nextProblem() } @IBAction func btnAction(_ sender: UIButton) { // 正解とボタンのタグ番号が同じなら正解 if sender.tag == Int(questionArray[1]) { answerImage.image = UIImage(named: "correct.png") //配列の最後の値を0に変更する questionArray[6] = "0" //色なしの星をセットする star.setImage(image0, for: .normal) correctCount += 1 } else { answerImage.image = UIImage(named: "incorrect.png") //配列の最後の値を1に変更する questionArray[6] = "1" //色付きの星をセットする star.setImage(image1, for: .normal) } answerImage.isHidden = false DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { self.answerImage.isHidden = true } questionCount += 1 nextProblem() } @IBAction func Next(_ sender: Any) { if questionCount < total { questionCount += 1 nextProblem() } } @IBAction func Previous(_ sender: Any) { if questionCount > 0{ questionCount -= 1 nextProblem() } } func nextProblem() { questionArray.removeAll(keepingCapacity: true) if questionCount < total { questionArray = csvArray[questionCount].components(separatedBy: ",") quizNumberLabel.text = "第(questionCount+1)問" quizQuestionLabel.text = questionArray[0] uiButton1.setTitle(questionArray[2], for: .normal) uiButton2.setTitle(questionArray[3], for: .normal) uiButton3.setTitle(questionArray[4], for: .normal) uiButton4.setTitle(questionArray[5], for: .normal) } else { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { self.performSegue(withIdentifier: "toResultViewController", sender: nil) } } } // 星をタップした場合の動作 @IBAction func starTapped(_ sender: Any) { questionArray.removeAll(keepingCapacity: true) questionArray = csvArray[questionCount].components(separatedBy: ",") count += 1 if(count%2 == 0){ questionArray[6] = "0" star.setImage(image0, for: .normal) } else if(count%2 == 1){ questionArray[6] = "1" star.setImage(image1, for: .normal) } } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { let sVC: ResultViewController = (segue.destination as? ResultViewController)! sVC.correct = correctCount } func loadCSV(filename : String)->[String] { var csvStr = [String]() if let csvPath = Bundle.main.path(forResource: filename, ofType: "csv") { do { var csvData = try String(contentsOfFile: csvPath, encoding: String.Encoding.utf8) csvData = csvData.replacingOccurrences(of: "\n", with: "") csvStr = csvData.components(separatedBy: .newlines) } catch let error as NSError { print(error.localizedDescription) } } return csvStr } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } }

アドバイスいだけますと助かります。
どうぞよろしくお願いいたします。

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

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

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

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

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

thyda.eiqau

2019/10/18 00:39

「変更されても毎回保存されていないような状況」とのことですが、保存する処理はどこに書いているのですか?ご提示のコードの中には見当たりませんが
guest

回答1

0

func nextProblem() {
questionArray = csvArray[questionCount].components(separatedBy: ",")

出題時に上記のようにquestionArrayを毎回元のCSVから生成しなおしているので、
いくらquestionArray[6] = "1"などを実行しても、その情報はメモリ上へ残りません。

解決方法の方針ですが、まず1問だけを扱うクラス(または構造体)を作ってください。

swift

1class Question { 2 /// 英単語 3 var word = "" 4 /// 正解のインデックス 5 var answerIndex = 0 6 /// 選択肢 7 var choices = [String]() 8 /// 星 9 var isStar = false 10}

あとは一度だけCSVファイルを解析し、上記クラスの配列として全問題をメンバー変数へ保持してください。

/// 全問題 var questions = [Question]() 理想はこう viewDidLoad() { ... questions = loadCSV() }

あとは、クリアしたら各QuestionのisStarフラグをtrue/falseにするだけで、情報をメモリ上へ保持できます。

また、問題提出時にはこのisStarフラグを見てUIの星の画像を差し替えることも忘れずに。
(たぶん現状はその処理もやっていません)

投稿2019/10/18 00:44

編集2019/10/18 01:56
takabosoft

総合スコア8356

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問