如何在swift中记录日期,时间和分数

时间:2016-02-06 19:32:42

标签: ios swift nsdate

我正在创建一个简单的测验应用。我打算展示某种历史"用户可以看到以下内容:

  1. 比赛日期和时间
  2. 该特定会话的分数
  3. 我该怎么做?

    截至播放的日期和时间,我在SO上看到了这个帖子:How to get the current time as datetime 但是,我如何" RECORD"用户玩游戏的日期和时间?

    关于分数数据,我正在使用:

    NSUserDefaults.standardUserDefaults().setInteger(currentScore, forKey: "score")
    

    但是,我只能获得当前的分数。如何记录用户在不同日期和时间内获得的分数?

    请注意,我在获取用户的当前分数方面没有任何问题。我需要帮助在多个会话中存储或记录用户的分数。

    例如,我想要显示如下内容:

    Date: 2/7/16
    Time: 7:00 AM
    Score: 70/100
    

3 个答案:

答案 0 :(得分:0)

要存储每个会话的分数,您需要与每个用户关联的某种数据结构。您可以使用将日期与分数相关联的键值对字典。这样,您就可以为用户存储的每个日期得分。

答案 1 :(得分:0)

您需要使用数据库来存储具有未定义记录数的此类数据。 查看Apple here

的核心数据编程指南

然后,您可以创建一个名为history的实体,您可以通过在每次用户完成游戏时将新对象插入实体来存储用户游戏历史记录。

当您需要显示结果时,您需要在NSFetchRequest上创建NSManagedObjectContext以获取所有结果,并根据需要显示/过滤它们。

希望有所帮助!

答案 2 :(得分:0)

NSUserDefaults可能不适合您要做的事情。我建议使用NSCoding进行简单的数据存储。对于这么简单的事情,核心数据可能过于复杂。但是,如果您计划保存具有关系的大型数据模型,则可以使用Core Data。

NSCoding

NSCoding有两部分:

  1. 编码和解码
  2. 归档和取消归档
  3. NSHipster完美地解释了这一点:

      

    NSCoding是一个简单的协议,有两种方法:-initWithCoder:和encodeWithCoder:。符合NSCoding的类可以序列化和反序列化为可以存档到磁盘或通过网络分布的数据。

    归档由NSKeyedArchiverNSKeyedUnarchiver执行。

    会话

    即使没有NSCoding,也建议用对象表示数据。在这种情况下,我们可以使用非常有创意的名称Session来表示历史记录中的会话。

    class Session: NSObject, NSCoding {
    
        let date: NSDate // stores both date and time
        let score: Int
    
        init(date: NSDate, score: Int) { // initialize a NEW session
    
            self.date = date
            self.score = score
    
            super.init()
    
        }
    
        required init?(coder aDecoder: NSCoder) { // decodes an EXISTING session
    
            if let decodedDate = aDecoder.decodeObjectForKey("date") as? NSDate {
                 self.date = decodedDate
            } else {
                 self.date = NSDate() // placeholder // this case shouldn't happen, but clearing compiler errors
            }
    
            self.score = aDecoder.decodeIntegerForKey("score")
    
        }
    
        func encodeWithCoder(aCoder: NSCoder) {
    
            aCoder.encodeObject(date, forKey: "date")
            aCoder.encodeInteger(score, forKey: "score")
    
        }
    
    }
    

    上面的英文代码,从上到下依次为:

    • 定义班级,符合NSCoding
    • 会话的属性:日期(+时间)和分数
    • 新会话的初始化程序 - 只需要一个日期和分数并为其创建会话
    • 现有会话所需的初始化程序 - 解码保存的日期和分数
      • decodeObjectForKey:只是执行它所说的内容(使用键对对象进行解码),然后返回AnyObject?
      • 但是,
      • decodeIntegerForKey:会返回Int。如果文件中不存在,则返回0,这就是它不可选的原因。除了decodeObjectForKey:
      • 之外,大多数解码方法都是这种情况
    • 编码现有会话所需的方法 - 对日期和分数进行编码
      • 编码方法与解码方法一样简单。

    负责Session类,并为NSCoding准备好属性。当然,您总是可以添加更多属性和方法。

    SessionHistory

    虽然会话本身很好,但是需要一个管理会话数组的对象,它还需要符合NSCoding。您也可以将此代码添加到现有类中。

    class SessionHistory: NSObject, NSCoding {
    
        var sessions = [Session]()
    
        required init?(coder aDecoder: NSCoder) {
    
            if let decodedSessions = aDecoder.decodeObjectForKey("sessions") as? [Session] {
                 self.sessions = decodedSessions
            } else {
                 self.sessions = [] // another compiler error clearer
            }
    
        }
    
        func encodeWithCoder(aCoder: NSCoder) {
    
            aCoder.encodeObject(sessions, forKey: "sessions")
    
        }
    
        override init() { // Used for convenience
            super.init()
        }
    
    }
    

    英文翻译:

    • 定义经理,符合NSCoding
    • 为会话数组添加属性
    • 接下来两个NSCoding方法与Session几乎完全相同。除了这个时候,它是一个数组。
    • 新经理的初始化程序,将在下面使用。

    NSCoding查看此管理器类并发现它需要对会话数组进行编码,因此NSCoding查看Session类以查看对这些会话编码的内容。

    NSKeyedArchiver / NSKeyedUnarchiver和Singletons

    虽然现在已设置了所有NSCoding,但最后一步是合并NSKeyedArchiverNSKeyedUnarchiver以实际保存和加载数据。

    两个重要方法是NSKeyedArchiver.archiveRootObject(_, toFile:)NSKeyedUnarchiver.unarchiveRootObjectWithFile:

    请注意,这两种方法都需要一个文件。它会自动为您创建文件,但您需要设置一个位置。将其添加到SessionHistory

    static var dataPath: String {
    
        let URLs = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
        let URL = URLs[0]
        return URL.URLByAppendingPathComponent("savehistory").path! // Put anything you want for that string
    
    }
    

    只是找到文件的位置。当然,您可以在其他地方找到放置文件。

    准备好数据路径后,您可以使用前面提到的两种方法。我喜欢在管理器类中使用单例的修改版本,以确保我使用相同的对象数组。在SessionHistory课程中:

    private static var history: SessionHistory!
    
    static func appHistory() -> SessionHistory {
    
        if history == nil {
            if let data = NSKeyedUnarchiver.unarchiveObjectWithFile(dataPath) as? SessionHistory {
                history = data
            } else {
                history = SessionHistory()
            }
        }
    
        return history
    
    }
    

    这将创建一个私有静态属性来存储应用程序的一个会话历史记录。静态方法检查会话历史记录是否为nil。如果是这样,它将返回文件中的当前历史记录并将该文件加载到history属性中。否则,它会创建一个新的空会话历史记录。之后,或者如果history属性已经存储了某些内容,它将返回history属性。

    用法

    NSCodingNSKeyedArchiver的所有设置都已完成。但是你如何使用这段代码?

    每次要访问会话历史记录时,请致电

    SessionHistory.appHistory()
    

    无论您想要保存会话历史记录,请致电

    NSKeyedArchiver.archiveRootObject(SessionHistory.appHistory(), toFile: SessionHistory.dataPath)
    

    示例使用方式如下:

    let session = Session(date: someRandomDate, score: someRandomScore)
    SessionHistory.appHistory().sessions.append(session)
    NSKeyedArchiver.archiveRootObject(SessionHistory.appHistory(), toFile: SessionHistory.dataPath)
    

    通过SessionHistory.appHistory()访问时,会自动从文件加载会话历史记录。

    你真的不需要"链接"这些类本身,你只需要将会话附加到会话历史的sessions数组。

    进一步阅读