我正在创建一个简单的测验应用。我打算展示某种历史"用户可以看到以下内容:
我该怎么做?
截至播放的日期和时间,我在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
答案 0 :(得分:0)
要存储每个会话的分数,您需要与每个用户关联的某种数据结构。您可以使用将日期与分数相关联的键值对字典。这样,您就可以为用户存储的每个日期得分。
答案 1 :(得分:0)
您需要使用数据库来存储具有未定义记录数的此类数据。 查看Apple here
的核心数据编程指南然后,您可以创建一个名为history
的实体,您可以通过在每次用户完成游戏时将新对象插入实体来存储用户游戏历史记录。
当您需要显示结果时,您需要在NSFetchRequest
上创建NSManagedObjectContext
以获取所有结果,并根据需要显示/过滤它们。
希望有所帮助!
答案 2 :(得分:0)
NSUserDefaults
可能不适合您要做的事情。我建议使用NSCoding
进行简单的数据存储。对于这么简单的事情,核心数据可能过于复杂。但是,如果您计划保存具有关系的大型数据模型,则可以使用Core Data。
NSCoding
有两部分:
NSHipster完美地解释了这一点:
NSCoding是一个简单的协议,有两种方法:-initWithCoder:和encodeWithCoder:。符合NSCoding的类可以序列化和反序列化为可以存档到磁盘或通过网络分布的数据。
归档由NSKeyedArchiver
和NSKeyedUnarchiver
执行。
即使没有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
准备好属性。当然,您总是可以添加更多属性和方法。
虽然会话本身很好,但是需要一个管理会话数组的对象,它还需要符合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
类以查看对这些会话编码的内容。
虽然现在已设置了所有NSCoding
,但最后一步是合并NSKeyedArchiver
和NSKeyedUnarchiver
以实际保存和加载数据。
两个重要方法是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属性。
NSCoding
和NSKeyedArchiver
的所有设置都已完成。但是你如何使用这段代码?
每次要访问会话历史记录时,请致电
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
数组。
NSCoding
的简单介绍。NSCoding
。