簡體   English   中英

如何在Swift中使用NSCoding存儲從ViewController生成的值

[英]How to store value generated from a ViewController using NSCoding in Swift

我有來自“ ScoreHistory.swift”的以下變量:

// ScoreHistory.swift

class ScoreHistory: NSObject, NSCoding {

var datePlayed: NSDate
var totalScore: Int
var totalAnswered: Int
var totalDuration: Int
var gameStatus: String

在我的QuizViewController中,我具有以下變量:

// QuizViewController.swift

var datePlayed = NSDate()
var totalScore = 0
var totalAnswered = 0
var totalDuration = 0
var gameStatus: String?

在每個游戲會話之后,用戶可能會獲得以下信息:(將顯示在“ ScoreViewController”中)

// Example data

datePlayed: (date today)
totalScore: 10
totalAnswered: 15
totalDuration: 1 min. 3 sec.
gameStatus: Exam Finished

我需要從QuizViewController獲得以上數據以存儲到“ ScoreHistory.swift”,我需要將數據顯示在ScoreViewController.swift中:

// ScoreViewController.swift

class ScoreViewController: UIViewController, UINavigationControllerDelegate {

// in viewDidLoad()

if let score = score {

    navigationItem.title = score.datePlayed.description
    datePlayedLabel.text = score.datePlayed.description
    totalScoreLabel.text   = score.totalScore.description
    totalAnsweredLabel.text   = score.totalAnswered.description
    totalDurationLabel.text   = score.totalDuration.description
    gameStatusLabel.text   = score.gameStatus
}

如何將生成的數據從QuizViewContoller存儲到ScoreHistory? 以及如何將上述數據顯示到ScoreViewController?

我的ScoreHistory看起來像這樣:

class ScoreHistory: NSObject, NSCoding {

// MARK: Properties

var datePlayed: NSDate
var totalScore: Int
var totalAnswered: Int
var totalDuration: Int
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: NSDate, totalScore: Int, totalAnswered: Int, totalDuration: Int, gameStatus: String) {
    // Initialize stored properties.

    self.datePlayed = datePlayed
    self.totalScore = totalScore
    self.totalAnswered = totalAnswered
    self.totalDuration = totalDuration
    self.gameStatus = gameStatus


    super.init()

    // Initialization should fail if there is no name or if the rating is negative.
    if gameStatus.isEmpty {
        return nil
    }
}

// MARK: NSCoding

func encodeWithCoder(aCoder: NSCoder) {

    aCoder.encodeObject(datePlayed, forKey: PropertyKey.datePlayedKey)
    aCoder.encodeInteger(totalScore, forKey: PropertyKey.totalScoreKey)
    aCoder.encodeInteger(totalAnswered, forKey: PropertyKey.totalAnsweredKey)
    aCoder.encodeInteger(totalDuration, forKey: PropertyKey.totalDurationKey)
    aCoder.encodeObject(gameStatus, forKey: PropertyKey.gameStatusKey)
}

required convenience init?(coder aDecoder: NSCoder) {

    let datePlayed = aDecoder.decodeObjectForKey(PropertyKey.datePlayedKey) as? NSDate
    let totalScore = aDecoder.decodeIntegerForKey(PropertyKey.totalScoreKey)
    let totalAnswered = aDecoder.decodeIntegerForKey(PropertyKey.totalAnsweredKey)
    let totalDuration = aDecoder.decodeIntegerForKey(PropertyKey.totalDurationKey)
    let gameStatus = aDecoder.decodeObjectForKey(PropertyKey.gameStatusKey) as! String

    // Must call designated initializer.
    self.init(datePlayed: datePlayed!, totalScore: totalScore, totalAnswered: totalAnswered, totalDuration: totalDuration, gameStatus: gameStatus)
}

}

我不確定我是否正確理解您的問題。 您的問題是:

  1. 如何將分數歷史記錄存儲到文件中。
  2. 如何將更改的信息從一個視圖控制器獲取到另一視圖控制器。

根據您提供的代碼,我無法弄清楚。

對1的答案。您已正確實現ScoreHistory類中的NSCoding方法。 我在這里假設這是您的模型類,必須包含整個游戲中收集的數據。 要將數據保存到文件中,只需使用NSKeyedArchiver對象。 該代碼的示例是:

    func saveStatisticsToDisk() {
    let isSuccessfulSave = NSKeyedArchiver.archiveRootObject(savedScore, toFile: ScoreHistory.scoreStore.path!)

    if !isSuccessfulSave {
        //Set the alert properties.
        let title = "Warning"
        let message = "Unable to save the scores"
        let animationFlag = true

        //configure the alert.
        let alertMessage = UIAlertController.init(title: title, message: message, preferredStyle: .Alert)
        let okAction = UIAlertAction(title: "Ok", style: .Default) {
            (action) -> Void in
            self.presentingViewController?.dismissViewControllerAnimated(animationFlag, completion: nil)
        }
        alertMessage.addAction(okAction)

        //Present the alert.
        self.presentViewController(alertMessage, animated: animationFlag, completion: nil)
    }
}

答案2。這更加復雜,因為您希望將數據從一個視圖控制器獲取到另一個視圖控制器。 編碼最佳實踐表明,您應該使用NSNotifications來通知從一個視圖控制器到另一個視圖控制器的更改。 這對於防止強參考循環是必要的。

這意味着在QuizViewController中,您具有ScoreHistory類的實例。 我們稱之為“ quizScoreHistory”。 在測驗期間,實例quizScoreHistory會更新,並且玩家完成某個關卡后,或者如您所說:“完成會話后”,ScoreViewController需要知道“ quizScoreHistory”的詳細信息,以便可以顯示信息給玩家。

我在這里向您展示如何使用標准NSNotification的字典userInfo來執行此操作。 在類QuizViewController中,使用以下代碼將通知放置在默認通知中心中:

    func notifyOnTrackChanges() {
//This function makes a dictionary with the key value pairs that reflect your ScoreHistory class.
//The a notification is posted under the name "scoreDidChange" posting the dictionary as userInfo. 
//The ScoreOverviewController will pick this up and store the values in the score to be displayed.

    let userInfo : [String: String] = ["date played": dateformatter.stringFromDate((self.quizScoreHistory.datePlayed)!), "total score": String((self.quizScoreHistory.totalScore)!), "total answered": String((self.quizScoreHistory.totalAnswered)!), "total duration": String((self.quizScoreHistory.gameStatus)!), "game status": String((self.quizScoreHistory.gameStatus)!)]
    let trackDetailNotificationCenter = NSNotificationCenter.defaultCenter()
    trackDetailNotificationCenter.postNotificationName("scoreDidChange", object: self, userInfo: userInfo)
}

我在這里將userInfo作為字符串放在字典中,因為您只想在ScoreViewController中進行顯示,並理解您提供的代碼,您只需要獲取得分歷史記錄作為字符串即可在單元格中顯示。

現在,您想在ScoreViewController中接收通知。 可以執行此操作以在viewDidLoad,viewWillAppear中實現以下代碼,或者更好地將其編寫為SetHistory實例中的setter。

        //This is the observer created to get the changes back from the QuizViewController.
    let notificationCenter = NSNotificationCenter.defaultCenter()
    let operationsQueue = NSOperationQueue.mainQueue()
    self.scoreChangedObserver = notificationCenter.addObserverForName("scoreDidChange", object: nil, queue: operationsQueue, usingBlock: { (notification: NSNotification!) -> Void in

        let score.datePlayed = notification.userInfo!["date played"]!
        let score.totalScore = notification.userInfo!["total score"]!
        let score.totalAnswered = notification.userInfo!["total answered"]!
        let score.totalDuration = notification.userInfo!["total duration"]!
        let score.gameStatus = notification.userInfo!["gameStatus"]!

        self.displayScore()
    })

然后,假設顯示得分是該方法的屬性,則顯示得分可能看起來像您在問題中提供的那樣:

func displayScore() {
    if let score = score {

        navigationItem.title = score.datePlayed
        datePlayedLabel.text = score.datePlayed
        totalScoreLabel.text   = score.totalScore
        totalAnsweredLabel.text   = score.totalAnswered
        totalDurationLabel.text   = score.totalDuration
        gameStatusLabel.text   = score.gameStatus
    }
}

我希望這會有所幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM