クイズアプリ開発入門書を書きました。

【Swift5/Xcode】入門編!クイズアプリを作成してみよう!参考書より丁寧に解説します。【Part5】

サトリク

前回の講座を受けていない方はこちらから

 

今の状態

サトリク

今の状況としては、

  • スタート画面でスタートを押すと、問題画面に遷移する
  • 問題画面で選択肢を押すと、コンソール上で正誤判定が行われ、次の画面問題がセットされる
  • 問題全て解くと、スコア画面に遷移する

ざっとこんな感じだと思います!

Part5では、主にスコア画面を完成させましょう!

スコア画面に正解数を表示し、トップに戻るボタンで、トップに戻るようにしましょう。

 

 

スコア画面でトップに戻るボタン実装

まずは、スコア画面でトップに戻るボタンを押したらトップに戻るようにしましょう。

STEP.1
Main.storyboardを選択

左のメニューからMain.storyboardを選択してください。

STEP.2
スコア画面とスコア画面のプログラムファイルを2分割

オブジェクトを紐づけるために、スコア画面とスコア画面のプログラムファイルを2分割で表示させましょう。

①スコア画面の上のバーをクリック

command + option + control + enterで2分割

STEP.3
「トップに戻る」ボタンを紐づけ

「トップに戻る」ボタンをコードと紐付けましょう。

controlを押しながら、override func viewDidLoad() {のブロックの外にドラッグ&ドロップ

 

NameにtoTopButtonActionと入力し、Connect

STEP.4
ScoreViewController.swiftを選択

左のメニューからScoreViewController.swiftを選択しましょう。

STEP.5
トップに戻る処理

先程接続してできた、ボタンを押したら呼ばれるブロックに以下のコードを記述しましょう。

@IBAction func toTopButtonAction(_ sender: Any) {
    self.presentingViewController?.presentingViewController?.dismiss(animated: true)
}

この1行は2つ前の画面に戻るという処理です。

STEP.6
実行して確認

左上の再生ボタンを押して、実行して確認しましょう。

クイズを行い、トップに戻るを押したら、このようにトップに戻れたら成功です!

完了

これでトップ画面に戻る処理ができました。

 

スコアをカウントしてコンソールに表示させる

次は、正解した数を数えてコンソールに表示させていきたいと思います。

STEP.1
QuizViewController.swiftを選択

左のメニューからQuizViewController.swiftを選択してください。

STEP.2
正解した数を入れていく箱を用意

var quizCount = 0の下に以下のコードを記述してください。

var correctCount = 0

正解したら、この値に1プラスしていきます。

STEP.3
正解したらcorrectCountに1プラスする

ボタンを押したときに呼ばれるブロックを以下のように書き換えましょう。

@IBAction func btnAction(sender: UIButton) {
    if sender.tag == Int(quizArray[1]) {
        correctCount += 1
        print("正解")
    } else {
        print("不正解")
    }
    print("スコア:\(correctCount)")
    nextQuiz()
}

正解したら、correctCountに1プラスしています。

そして、正誤判定が終わったら、コンソールに現在のスコアを表示しています。

STEP.4
実行して確認

実行して問題を解いてみましょう。

おそらく、コンソールにスコアが表示されるはずです。

完了

次は、このスコアをスコア画面に表示しましょう。

が、しかしcorrectCountは、QuizViewController.swiftの中にあるので、スコア画面では使えません。

なので、まず、スコア画面にcorrectCountを渡す処理を書いていきましょう。

 

スコア画面に値を渡してスコアを表示させる

STEP.1
ScoreViewController.swiftを選択

左のメニューからScoreViewController.swiftを選択

STEP.2
受け取る箱を用意

まずは、ScoreViewController.swiftで受け取る箱を用意します。

Classの下に以下のコードを記述しましょう。

var correct = 0

この箱にQuizViewController.swiftcorrectCount遷移するときに代入したいと思います。

STEP.3
QuizViewController.swiftを選択

左のメニューからQuizViewController.swiftを選択してください。

STEP.4
値を渡す

画面遷移するときに、値を渡すコードを記述します。

viewDidLoad()ブロックの下に以下のコードを記述してください。

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let scoreVC = segue.destination as! ScoreViewController
    scoreVC.correct = correctCount
}

これで、スコア画面で正解した数を取得できるようになったので、あとはLabelに表示させるだけです。

STEP.5
Main.storyboardを選択

左のメニューからMain.storyboardを選択してください。

STEP.6
Labelを広げる

枠が狭すぎて文字が…にならないように枠を広げておきましょう。

①Labelの枠を広げる

② (Show the Attributes inspector)を選択

Alignmentを中央揃えに変更

STEP.7
コードと2分割表示

①スコア画面の上のバーを選択

command + option + control + enterで2分割

STEP.8
Labelを紐付け

controlを押しながら、labelをclassの下にドラッグ&ドロップしましょう。

 

NameにscoreLabelと入力し、Connect

STEP.9
ScoreViewController.swiftを選択

左のメニューからScoreViewController.swiftを選択

STEP.10
Labelに正解数を代入

QuizViewController.swiftから受け取った値を先程紐付けたscoreLabelに代入します。

viewDidLoad()に以下の1行を記述してください。

scoreLabel.text = "\(correct)問正解!"

STEP.11
実行して確認

このように、問題が終わると「◯問正解!」と表示されるはずです!

完了

これでスコア画面が一通りできました!

 

ここまでの全コード

QuizViewController

import UIKit

class QuizViewController: UIViewController {
    @IBOutlet var quizNumberLabel: UILabel!
    @IBOutlet var quizTextView: UITextView!
    @IBOutlet var answerButton1: UIButton!
    @IBOutlet var answerButton2: UIButton!
    @IBOutlet var answerButton3: UIButton!
    @IBOutlet var answerButton4: UIButton!
    
    var csvArray: [String] = []
    var quizArray: [String] = []
    var quizCount = 0
    var correctCount = 0

    override func viewDidLoad() {
        super.viewDidLoad()
        
        csvArray = loadCSV(fileName: "quiz")
        print(csvArray)
        
        quizArray = csvArray[quizCount].components(separatedBy: ",")
        quizNumberLabel.text = "第\(quizCount + 1)問"
        quizTextView.text = quizArray[0]
        answerButton1.setTitle(quizArray[2], for: .normal)
        answerButton2.setTitle(quizArray[3], for: .normal)
        answerButton3.setTitle(quizArray[4], for: .normal)
        answerButton4.setTitle(quizArray[5], for: .normal)

        // Do any additional setup after loading the view.
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let scoreVC = segue.destination as! ScoreViewController
        scoreVC.correct = correctCount
    }
    
    //ボタンを押したときに呼ばれる
    @IBAction func btnAction(sender: UIButton) {
        if sender.tag == Int(quizArray[1]) {
            correctCount += 1
            print("正解")
        } else {
            print("不正解")
        }
        print("スコア:\(correctCount)")
        nextQuiz()
    }
    
    func nextQuiz() {
        quizCount += 1
        if quizCount < csvArray.count {
            quizArray = csvArray[quizCount].components(separatedBy: ",")
            quizNumberLabel.text = "第\(quizCount + 1)問"
            quizTextView.text = quizArray[0]
            answerButton1.setTitle(quizArray[2], for: .normal)
            answerButton2.setTitle(quizArray[3], for: .normal)
            answerButton3.setTitle(quizArray[4], for: .normal)
            answerButton4.setTitle(quizArray[5], for: .normal)
        } else {
            performSegue(withIdentifier: "toScoreVC", sender: nil)
        }
    }
    
    func loadCSV(fileName: String) -> [String] {
        let csvBundle = Bundle.main.path(forResource: fileName, ofType: "csv")!
        do {
            let csvData = try String(contentsOfFile: csvBundle,encoding: String.Encoding.utf8)
            let lineChange = csvData.replacingOccurrences(of: "\r", with: "\n")
            csvArray = lineChange.components(separatedBy: "\n")
            csvArray.removeLast()
        } catch {
            print("エラー")
        }
        return csvArray
    }

    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destination.
        // Pass the selected object to the new view controller.
    }
    */

}

ScoreViewController

import UIKit

class ScoreViewController: UIViewController {
    @IBOutlet var scoreLabel: UILabel!
    
    var correct = 0

    override func viewDidLoad() {
        super.viewDidLoad()
        
        scoreLabel.text = "\(correct)問正解!"

        // Do any additional setup after loading the view.
    }
    
    @IBAction func toTopButtonAction(_ sender: Any) {
        self.presentingViewController?.presentingViewController?.dismiss(animated: true)
    }
    
    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destination.
        // Pass the selected object to the new view controller.
    }
    */

}

 

クイズアプリを作ろうPert5まとめ

 

まとめ
  • self.presentingViewController?.presentingViewController?.dismiss(animated: true)で2つ前の画面に戻る
  • prepareメソッドで、画面遷移時に値を渡せる

 

一緒に楽しく雑談しながらアプリ開発しませんか?

RikutoSato

satorikublogの筆者がアプリ開発をマンツーマンでサポートします。

あなたのクイズアプリをAppStoreにリリースするまで、チャットや、ビデオ通話で楽しく雑談でもしながらサポートします。エラーで先に進まない方や、アイデアはあるけど、そのアイデアをアプリに実現できない方など、気軽にご相談ください!

詳しくはこちら