I need to save data from a segued ViewController (“ScoreView.swift”) to “ScoreHistory.swift” using NSCoding. I tried but the data isn't showing up in "ScoreTableViewController.swift". What am I missing?
I have this ScoreView.swift which has the following code: (Pls note that this is a "segued" view where data has been passed from another ViewController)
class ScoreView: UIViewController {
var dateToday = NSDate()
var score: ScoreHistory?
var numberofquestions:String = ""
var scorepassed:String = ""
var scorepercentpassed:String = ""
var scoreremarkspassed:String = ""
var totalduration:String!
var incorrectanswerspassed:String = ""
var skippedquestionspassed:String = ""
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
datePlayedLabel.text = dateToday.description
totalScoreLabel.text = scorepassed
scorePercentage.text = scorepercentpassed
totalAnsweredLabel.text = numberofquestions
totalDurationLabel.text = totalduration
gameStatusLabel.text = "Exam Finished"
// NSCoding
if let score = score {
datePlayedLabel.text = score.datePlayed
totalScoreLabel.text = score.totalScore
totalAnsweredLabel.text = score.totalAnswered
totalDurationLabel.text = score.totalDuration
gameStatusLabel.text = score.gameStatus
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if backMenu === sender {
let datePlayed = datePlayedLabel.text ?? ""
let totalScore = totalScoreLabel.text ?? ""
let totalAnswered = totalAnsweredLabel.text ?? ""
let totalDuration = totalDurationLabel.text ?? ""
let gameStatus = gameStatusLabel.text ?? ""
// Set the score to be passed to ScoreTableViewController after the unwind segue.
score = ScoreHistory(datePlayed: datePlayed, totalScore: totalScore, totalAnswered: totalAnswered, totalDuration: totalDuration, gameStatus: gameStatus)
}
NSKeyedArchiver.archiveRootObject(score!, toFile: ScoreHistory.ArchiveURL.path!)
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(true)
datePlayedLabel.text = dateToday.description
totalScoreLabel.text = scorepassed
scorePercentage.text = scorepercentpassed
totalAnsweredLabel.text = numberofquestions
totalDurationLabel.text = totalduration
gameStatusLabel.text = "Exam Finished"
}
// Labels
}
}
I have ScoreHistory.swift, which has the following code:
class ScoreHistory: NSObject, NSCoding {
// MARK: Properties
var datePlayed: String
var totalScore: String
var totalAnswered: String
var totalDuration: String
var gameStatus: String
// MARK: Archiving Paths
static let DocumentsDirectory = NSFileManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first!
static let ArchiveURL = DocumentsDirectory.URLByAppendingPathComponent("scores")
// MARK: Types
struct PropertyKey {
static let datePlayedKey = "datePlayed"
static let totalScoreKey = "totalScore"
static let totalAnsweredKey = "totalAnswered"
static let totalDurationKey = "totalDuration"
static let gameStatusKey = "gameStatus"
}
// MARK: Initialization
init?(datePlayed: String, totalScore: String, totalAnswered: String, totalDuration: String, gameStatus: String) {
// Initialize stored properties.
self.datePlayed = datePlayed
self.totalScore = totalScore
self.totalAnswered = totalAnswered
self.totalDuration = totalDuration
self.gameStatus = gameStatus
super.init()
}
// MARK: NSCoding
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(datePlayed, forKey: PropertyKey.datePlayedKey)
aCoder.encodeObject(totalScore, forKey: PropertyKey.totalScoreKey)
aCoder.encodeObject(totalAnswered, forKey: PropertyKey.totalAnsweredKey)
aCoder.encodeObject(totalDuration, forKey: PropertyKey.totalDurationKey)
aCoder.encodeObject(gameStatus, forKey: PropertyKey.gameStatusKey)
}
required convenience init?(coder aDecoder: NSCoder) {
let datePlayed = aDecoder.decodeObjectForKey(PropertyKey.datePlayedKey) as! String
let totalScore = aDecoder.decodeObjectForKey(PropertyKey.totalScoreKey) as! String
let totalAnswered = aDecoder.decodeObjectForKey(PropertyKey.totalAnsweredKey) as! String
let totalDuration = aDecoder.decodeObjectForKey(PropertyKey.totalDurationKey) as! String
let gameStatus = aDecoder.decodeObjectForKey(PropertyKey.gameStatusKey) as! String
// Must call designated initializer.
self.init(datePlayed: datePlayed, totalScore: totalScore, totalAnswered: totalAnswered, totalDuration: totalDuration, gameStatus: gameStatus)
}
}
Here is the full code of ScoreTableViewController.swift:
class ScoreTableViewController: UITableViewController {
// MARK: Properties
var scores = [ScoreHistory]()
var dateToday = NSDate()
override func viewDidLoad() {
super.viewDidLoad()
// Load any saved scores, otherwise load sample data.
if let savedScores = loadScores() {
scores += savedScores
} else {
// Load the sample data.
loadSampleScores()
}
}
func loadSampleScores() {
let score1 = ScoreHistory(datePlayed: dateToday.description, totalScore: "0", totalAnswered: "0", totalDuration: "0", gameStatus: "started")!
scores += [score1]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return scores.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// Table view cells are reused and should be dequeued using a cell identifier.
let cellIdentifier = "ScoreHistoryTableViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! ScoreHistoryTableViewCell
// Fetches the appropriate note for the data source layout.
let score = scores[indexPath.row]
cell.datePlayedLabel.text = score.datePlayed
cell.totalScoreLabel.text = score.datePlayed
cell.totalScoreLabel.text = score.totalScore
cell.totalAnsweredLabel.text = score.totalAnswered
cell.totalDurationLabel.text = score.totalDuration
cell.gameStatusLabel.text = score.gameStatus
return cell
}
// Override to support conditional editing of the table view.
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
// Override to support editing the table view.
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
// Delete the row from the data source
scores.removeAtIndex(indexPath.row)
saveScores()
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
}
}
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "ShowDetail" {
let scoreDetailViewController = segue.destinationViewController as! ScoreViewController
// Get the cell that generated this segue.
if let selectedScoreCell = sender as? ScoreHistoryTableViewCell {
let indexPath = tableView.indexPathForCell(selectedScoreCell)!
let selectedScore = scores[indexPath.row]
scoreDetailViewController.score = selectedScore
}
}
}
// MARK: NSCoding
func saveScores() {
let isSuccessfulSave = NSKeyedArchiver.archiveRootObject(scores, toFile: ScoreHistory.ArchiveURL.path!)
if !isSuccessfulSave {
print("Failed to save scores...")
}
}
func loadScores() -> [ScoreHistory]? {
return NSKeyedUnarchiver.unarchiveObjectWithFile(ScoreHistory.ArchiveURL.path!) as? [ScoreHistory]
}
@IBAction func unwindToScoreList(sender: UIStoryboardSegue) {
if let sourceViewController = sender.sourceViewController as? ScoreViewController, score = sourceViewController.score {
if let selectedIndexPath = tableView.indexPathForSelectedRow {
// Update an existing note.
scores[selectedIndexPath.row] = score
tableView.reloadRowsAtIndexPaths([selectedIndexPath], withRowAnimation: .None)
// Add a new score.
let newIndexPath = NSIndexPath(forRow: scores.count, inSection: 0)
scores.append(score)
tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Bottom)
saveScores()
}
}
}
}
GOAL: My goal is to record/store all session data from “ScoreView.swift” whenever a user finishes a quiz game. The "ScoreView" is shown after each quiz game, I plan to record each quiz results in "ScoreHistory.swift." How do I do it?