SWIFT struggling with value assignment to optional class variable [duplicate]

拟墨画扇 提交于 2021-01-29 18:21:17

问题


as an old C programmer I am trying to get into Swift. I have already overcome many hurdles but for the following I am out of ideas.

I am building a little home schooling app and want to store/retrieve the high scores to/from a JSON file.

import Foundation

struct HighScores: Codable {
    var Scores:Int
    var highscoreRecord: [HighscoreRecord]
}

struct HighscoreRecord: Codable {
    var Rank:Int
    var Date:String?
    var avDuration:Float?
    var Score:Int?
    var Tries:Int?
}

In order to read and write the Highscores, I have declared the JSON result as a variable in the view controller, not as a constant.

import UIKit
import Foundation

class GameplayViewController: UIViewController {

    //    var jsonResult: HighScores(Scores: 1, highscoreRecord.Rank: 1, highscoreRecord.Date: "00-00-00", highscoreRecord.avDuration: 0.0, highscoreRecord.Score: 0, highscoreRecord.Tries: 0)

    var jsonResult: HighScores?

In case no high scores are yet present (first app run), reading the JSON data fails and instead I want to save the gameplay result to the JSON file.

if firstHighscore == 1 {
            jsonResult!.Scores = 1
            jsonResult!.highscoreRecord[0].Rank = 1
            jsonResult!.highscoreRecord[0].Date = formatter.string(from: dateStart)
            jsonResult!.highscoreRecord[0].avDuration = Float(lblSpeed.text ?? "0.0")
            jsonResult!.highscoreRecord[0].Score = Int(lblRatio.text ?? "0")
            jsonResult!.highscoreRecord[0].Tries = hits + misses
        }

This fails in the row "jsonResult!.highscoreRecord[0].Rank = 1" with

Fatal error: Unexpectedly found nil while unwrapping an Optional value: file /Users/holger/Documents/xCode/1x1/1x1/1x1/GameplayViewController.swift, line 157

Any ideas why and how to avoid this?

Cheers Tom

PS: the whole code is

import UIKit
import Foundation

class GameplayViewController: UIViewController {

    var factor1 = 0
    var factor2 = 0
    var operation = ""
    var hits = 0
    var misses = 0
    var resultEntered: String = ""
    var dateStart =  Date()
//    var jsonResult: HighScores(Scores: 1, highscoreRecord.Rank: 1, highscoreRecord.Date: "00-00-00", highscoreRecord.avDuration: 0.0, highscoreRecord.Score: 0, highscoreRecord.Tries: 0)
    var jsonResult: HighScores?
    var updteHS = 0
    var i=0
    var firstHighscore=0

    @IBOutlet weak var btn1: UIButton!
    @IBOutlet weak var btn2: UIButton!
    @IBOutlet weak var btn3: UIButton!
    @IBOutlet weak var btn4: UIButton!
    @IBOutlet weak var btn5: UIButton!
    @IBOutlet weak var btn6: UIButton!
    @IBOutlet weak var btn7: UIButton!
    @IBOutlet weak var btn8: UIButton!
    @IBOutlet weak var btn9: UIButton!
    @IBOutlet weak var btn0: UIButton!
    @IBOutlet weak var btnGo: UIButton!
    @IBOutlet weak var btnStop: UIButton!
    @IBOutlet weak var lblTask: UILabel!
    @IBOutlet weak var lblResult: UILabel!
    @IBOutlet weak var lblHits: UILabel!
    @IBOutlet weak var lblMisses: UILabel!
    @IBOutlet weak var lblRatio: UILabel!
    @IBOutlet weak var lblSpeed: UILabel!
    @IBOutlet weak var btnDone: UIButton!





    @IBAction func goTapped(_ sender: Any) {
        if factor1 == 0 {
            btnGo.setTitle("los", for: .normal)
            lblTask.text = "Aufgabe"
            lblResult.text = "Ergebnis"
            dateStart =  Date()
   //         loadHighscores()
     //       for highscore in highscoreList {
       //         highScores.text = highscore.Date
       //     }

        }
        else {
            resultEntered = lblResult.text!
            if (operation == "x" ? factor1*factor2 : factor1/factor2) == Int(resultEntered) {
                hits += 1
                lblHits.text = String(hits)
            }
            else {
                misses += 1
                lblMisses.text = String(misses)
            }
            lblRatio.text = String(format: "%.0f", (Float(hits)/Float(hits+misses)*100)) + "%"
        lblSpeed.text = String(format: "%.1f", (-Float(dateStart.timeIntervalSinceNow) / Float(hits+misses))) + "s"
        }
        factor1 = Int.random(in: 1...10)
        factor2 = Int.random(in: 1...10)
        if Int(Float.random(in: 0...1.3)) == 0 {
            operation = "x"
        }
        else {
            operation = "/"
            factor1 = factor1 * factor2
        }

        lblTask.text = String(factor1) + " \(operation) " + String(factor2)
        lblResult.text = ""

    }
    @IBAction func btn1Tapped(_ sender: Any) {
        lblResult.text = String((Int(lblResult.text ?? "0") ?? 0)*10+1)
    }
    @IBAction func btn2Tapped(_ sender: Any) {
        lblResult.text = String((Int(lblResult.text ?? "0") ?? 0)*10+2)
    }
    @IBAction func btn3Tapped(_ sender: Any) {
        lblResult.text = String((Int(lblResult.text ?? "0") ?? 0)*10+3)
    }
    @IBAction func btn4Tapped(_ sender: Any) {
        lblResult.text = String((Int(lblResult.text ?? "0") ?? 0)*10+4)
    }
    @IBAction func btn5Tapped(_ sender: Any) {
        lblResult.text = String((Int(lblResult.text ?? "0") ?? 0)*10+5)
    }
    @IBAction func btn6Tapped(_ sender: Any) {
        lblResult.text = String((Int(lblResult.text ?? "0") ?? 0)*10+6)
    }
    @IBAction func btn7Tapped(_ sender: Any) {
        lblResult.text = String((Int(lblResult.text ?? "0") ?? 0)*10+7)
    }
    @IBAction func btn8Tapped(_ sender: Any) {
        lblResult.text = String((Int(lblResult.text ?? "0") ?? 0)*10+8)
    }
    @IBAction func btn9Tapped(_ sender: Any) {
        lblResult.text = String((Int(lblResult.text ?? "0") ?? 0)*10+9)
    }
    @IBAction func btn0Tapped(_ sender: Any) {
        lblResult.text = String((Int(lblResult.text ?? "0") ?? 0)*10)
    }
    @IBAction func doneTapped(_ sender: Any) {
        self.performSegue(withIdentifier: "HighScoreSegue", sender: self)
//    override func viewDidLoad() {
  //      super.viewDidLoad()


            // Decode original json

                do {
                    let fileURL = try FileManager.default
                               .url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
                               .appendingPathComponent("highscore.json")

                    let jsonData = try Data(contentsOf: fileURL)
                    let decoder = JSONDecoder()
                    self.jsonResult = try decoder.decode(HighScores.self, from: jsonData)

      /*              let jsonFileContents = try String(contentsOf: pathUrl, encoding: .utf8)
                    let lists = try JSONDecoder().decode(Lists.self, from: jsonFileContents.data(using: .utf8)!)

                    let jsonDecoder = JSONDecoder()
                    self.jsonResult = try jsonDecoder.decode(HighScores.self, from: data)*/
                }
                catch {
                    print ("Error in JSON parsing")
                    firstHighscore = 1

                }



            // Change status
        let formatter = DateFormatter()
        formatter.dateFormat = "y MMM d"

        if firstHighscore == 1 {
            jsonResult!.Scores = 1
            jsonResult!.highscoreRecord[0].Rank = 1
            jsonResult!.highscoreRecord[0].Date = formatter.string(from: dateStart)
            jsonResult!.highscoreRecord[0].avDuration = Float(lblSpeed.text ?? "0.0")
            jsonResult!.highscoreRecord[0].Score = Int(lblRatio.text ?? "0")
            jsonResult!.highscoreRecord[0].Tries = hits + misses
        }
        else {
            for i in 0..<(jsonResult?.highscoreRecord.count ??  0 )  {

                if updteHS == 0 {
                    if (Int(lblRatio.text ?? "0") ?? 0) > (jsonResult!.highscoreRecord[i].Score ?? 0) {
                        jsonResult!.highscoreRecord[i].Rank = i+1
                        jsonResult!.highscoreRecord[i].Date = formatter.string(from: dateStart)
                        jsonResult!.highscoreRecord[i].avDuration = Float(lblRatio.text ?? "0.0")
                        jsonResult!.highscoreRecord[i].Score = Int(lblRatio.text ?? "0")
                        jsonResult!.highscoreRecord[i].Tries = hits + misses
                    }
                    else if i < 10 {
                        jsonResult!.highscoreRecord[i+1].Rank = i+2
                        jsonResult!.highscoreRecord[i+1].Date = jsonResult!.highscoreRecord[i].Date
                        jsonResult!.highscoreRecord[i+1].avDuration = jsonResult!.highscoreRecord[i].avDuration
                        jsonResult!.highscoreRecord[i+1].Score = jsonResult!.highscoreRecord[i].Score
                        jsonResult!.highscoreRecord[i+1].Tries = jsonResult!.highscoreRecord[i].Tries
                    }
                }

            }
        }
        print(jsonResult)

        // Encode new updated json to data
        do {
            let encoder = JSONEncoder()
            var encodeData = try encoder.encode(jsonResult)
        }
        catch {
            print ("Error in JSON writing")
        }


//    }

    } 

}

来源:https://stackoverflow.com/questions/62130016/swift-struggling-with-value-assignment-to-optional-class-variable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!