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

サトリク

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

 

今の状態

サトリク

今の状況としては、

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

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

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

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

 

 

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

スコア画面の「トップに戻る」ボタンを実装していきましょう!

STEP.1
Main.storyboardを表示

 (show the Project navigator)を選択

Main.storyboardを選択

STEP.2
コード画面と2分割にする

①「トップに戻る」を選択

command + option + shift + enterで2分割

STEP.3
ボタンを接続

controlを押しながら、17行目と18行目の間にドラッグ&ドロップ

 

①「Name」にtoTopBtnActionと入力

②「Connect」をクリック

STEP.4
トップに戻る処理

先ほどの接続で、以下のようなメソッドが追加されました。

このメソッドは、「トップに戻る」ボタンを押したときに呼ばれます。

 

@IBAction func toTopBtnAction(_ sender: Any) {
}

 

このコードを以下のように書き換えてください。

 

@IBAction func toTopBtnAction(_ sender: Any) {
    self.presentingViewController?.presentingViewController?.dismiss(animated: true, completion: nil)
}

この1行を追加すると、トップに戻ることがきます。

STEP.5
実行して確認

左上のボタンを押すか、command + rで実行してトップボタンでスタート画面に戻れることを確認しましょう。

完了

確認ができたら、次にいきましょう!

 

コンソールにスコアを表示させる

スコアをコンソールに表示させてみたいと思います。

STEP.1
QuizViewController.swiftを表示

QuizViewController.swiftを選択

STEP.2
正解数を入れる変数を用意

正解数を入れる変数を用意します。

23行目あたり、var quizTotal = 5の下に以下のコードを追記してください。

 

var correctCount = 0

正解したら、このcorrectCountに1足していきます。

STEP.3
正解したらcorrectCountに1点ずつ入れるプログラム

正解したら、correctCountに1点ずつ入れていきましょう。

42行目あたりのbtnActionメソッドを以下のように書き換えましょう。

 

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

正解した場合に、correctCountに+1していきます。

正誤判定した後に、print関数でコンソールにスコアを表示します。

STEP.4
実行して確認

左上のボタンを押すか、command + rで実行してコンソールに、スコア:nと表示されることを確認しましょう!

完了
確認できたら完了です。次に進みましょう!

 

スコア画面でスコアを表示させる

先ほどコンソールに表示させたスコアをスコア画面に表示させましょう。

スコア画面でスコアを表示させる手順としては、

  1. QuizViewController.swiftで正解したら、correctCountに1を足してスコアを記録する
  2. QuizViewController.swiftで問題が終わった後の画面遷移と同時に、ScoreViewController.swift に correctCountを渡す
  3. ScoreViewController.swiftで、受け取った値をscoreLabelに代入する

です。

STEP.1
ScoreViewController.swiftを表示

ScoreViewController.swiftを選択

STEP.2
変数を追加

まずは、QuizViewController.swiftからcorrectCountを受け取るため箱(変数)を用意します。

12行目あたりに、class ScoreViewController: UIViewController {の下に以下のコードを追記しましょう。

 

var correct = 0

STEP.3
QuizViewController.swiftを表示

QuizViewController.swiftを選択

STEP.4
prepareメソッド追加

次に、画面遷移する際に、値を渡すための準備をします。

42行目あたり、}の下に以下のメソッドを追加してください。

 

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

これで、画面遷移時にScoreViewControllerの変数correctに、QuizViewControllercorrectCountを代入します。

STEP.5
Main.storyboardを表示

Main.storyboardを選択

STEP.6
Labelのレイアウト変更

①Labelを横いっぱいに広げる

② (Show the Attributes inspector)を選択

②Alignmentを中央揃え

STEP.7
コード画面と2分割にする

①Labelを選択

command + option + shift + enter2分割

STEP.8
Labelを紐付ける

controlを押しながら、10行目と11行目の間にドラッグ&ドロップ

 

①「Name」にscoreLabel

②「Connect」をクリック

STEP.8
scoreLabelにテキストを代入

15行目あたりのviewDidLoadメソッドを以下のように書き換えましょう。

override func viewDidLoad() {
    super.viewDidLoad()
    scoreLabel.text = "\(correct)問正解!"
    // Do any additional setup after loading the view.
}

これで、scoreLabelに○問正解!と表示されるようになります。

STEP.8
実行して確認

左上のボタンを押すか、command + rで実行して◯問正解!と表示されるか確認しましょう!

このように正解数が表示されるはずです。

完了

これで、スコア画面が完了しました!

ここまでの全コード

注意

丸々コピペしても、エラーが出る場合は、もう一度Part1からやり直した方がいいかもしれません。

Xcodeになれていない状態で、修正するのはかなり至難の技です。

QuizViewController

//
//  QuizViewController.swift
//  SampleQuiz
//
//  Created by RikutoSato on 2020/10/22.
//

import UIKit

class QuizViewController: UIViewController {
    
    @IBOutlet weak var quizNumberLabel: UILabel!
    @IBOutlet weak var quizTextView: UITextView!
    @IBOutlet weak var answerBtn1: UIButton!
    @IBOutlet weak var answerBtn2: UIButton!
    @IBOutlet weak var answerBtn3: UIButton!
    @IBOutlet weak var answerBtn4: UIButton!
    
    var csvArray: [String] = []
    var quizArray: [String] = []
    var quizCount = 0
    var quizTotal = 5
    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]
        answerBtn1.setTitle(quizArray[2], for: .normal)
        answerBtn2.setTitle(quizArray[3], for: .normal)
        answerBtn3.setTitle(quizArray[4], for: .normal)
        answerBtn4.setTitle(quizArray[5], for: .normal)

        // Do any additional setup after loading the view.
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let sVC = segue.destination as! ScoreViewController
        sVC.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
        quizArray.removeAll()
        if quizCount < quizTotal {
            quizArray = csvArray[quizCount].components(separatedBy: ",")
            quizNumberLabel.text = "第\(quizCount + 1)問"
            quizTextView.text = quizArray[0]
            answerBtn1.setTitle(quizArray[2], for: .normal)
            answerBtn2.setTitle(quizArray[3], for: .normal)
            answerBtn3.setTitle(quizArray[4], for: .normal)
            answerBtn4.setTitle(quizArray[5], for: .normal)
        } else {
            performSegue(withIdentifier: "scoreVC", 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")
        } 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

//
//  ScoreViewController.swift
//  SampleQuiz
//
//  Created by RikutoSato on 2020/10/22.
//

import UIKit

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

    override func viewDidLoad() {
        super.viewDidLoad()
        scoreLabel.text = "\(correct)問正解!"
        // Do any additional setup after loading the view.
    }
    
    @IBAction func toTopBtnAction(_ sender: Any) {
        self.presentingViewController?.presentingViewController?.dismiss(animated: true, completion: nil)
    }
    
    /*
    // 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.dismiss(animated: true, completion: nil)で画面遷移元に戻る
  • prepareメソッドで、画面遷移時に値を渡せる

 

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

RikutoSato

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

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

詳しくはこちら