问题
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