ios - How to record date, time, and score in swift -
i creating simple quiz app. planning show kind of "history" user can see following:
- date , time of playing
- score particular session
how do that?
as of date , time of playing, saw thread on so: how current time datetime however, how "record" date(s) , time(s) user played game?
regarding score data, using:
nsuserdefaults.standarduserdefaults().setinteger(currentscore, forkey: "score") however, able current score. how record score(s) user got each session on different date(s) , time(s)?
please note have no problem in getting user's current score. need in storing or recording user's score(s) in multiple sessions.
for instance, wanted display this:
date: 2/7/16 time: 7:00 score: 70/100
nsuserdefaults isn't right trying do. recommend using nscoding simple data storing. core data may complicated simple. however, if plan on saving large data model relationships, core data way go.
nscoding
nscoding has 2 parts:
- encoding , decoding
- archiving , unarchiving
nshipster explains perfectly:
nscoding simple protocol, 2 methods: -initwithcoder: , encodewithcoder:. classes conform nscoding can serialized , deserialized data can either archived disk or distributed across network.
that archiving performed nskeyedarchiver , nskeyedunarchiver.
session
even without nscoding, suggested represent data objects. in case, can use creative name session represent session in history.
class session: nsobject, nscoding { let date: nsdate // stores both date , time let score: int init(date: nsdate, score: int) { // initialize new session self.date = date self.score = score super.init() } required init?(coder adecoder: nscoder) { // decodes existing session if let decodeddate = adecoder.decodeobjectforkey("date") as? nsdate { self.date = decodeddate } else { self.date = nsdate() // placeholder // case shouldn't happen, clearing compiler errors } self.score = adecoder.decodeintegerforkey("score") } func encodewithcoder(acoder: nscoder) { acoder.encodeobject(date, forkey: "date") acoder.encodeinteger(score, forkey: "score") } } the above code in english, in order top bottom:
- defining class, conforming
nscoding - the properties of session: date (+ time) , score
- the initializer new session - takes date , score , creates session it
- the required initializer existing session - decodes date , score saved
decodeobjectforkey:says (decodes object using key), , returnsanyobject?decodeintegerforkey:, however, returnsint. if none exists on file, returns 0, why isn't optional. case of decoding methods exceptdecodeobjectforkey:
- the required method encoding existing session - encodes date , score
- the encoding methods straightforward decoding methods.
that takes care of session class, properties ready nscoding. of course, add more properties , methods.
sessionhistory
while sessions nice, object manage array of sessions needed, , needs conform nscoding. add code existing class.
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 = [] // compiler error clearer } } func encodewithcoder(acoder: nscoder) { acoder.encodeobject(sessions, forkey: "sessions") } override init() { // used convenience super.init() } } english translation:
- defining manager, conforming
nscoding - add property array of sessions
- next 2
nscodingmethods same thingsession. except time, array. - initializer new manager, used below.
nscoding looks @ manager class , sees needs encode array of sessions, nscoding looks @ session class see encode sessions.
nskeyedarchiver/nskeyedunarchiver , singletons
while nscoding set now, final step incorporate nskeyedarchiver , nskeyedunarchiver save , load data.
the 2 important methods nskeyedarchiver.archiverootobject(_, tofile:) , nskeyedunarchiver.unarchiverootobjectwithfile:
note both methods need file. automagically creates file you, need set location. add sessionhistory:
static var datapath: string { let urls = nsfilemanager.defaultmanager().urlsfordirectory(.documentdirectory, indomains: .userdomainmask) let url = urls[0] return url.urlbyappendingpathcomponent("savehistory").path! // put want string } that finds location file. could, of course, find somewhere else put file.
with data path ready, can use 2 methods mentioned earlier. use modified version of singleton manager class make sure i'm using same array of objects. in sessionhistory class:
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 } this creates private static property store 1 session history of app. static method checks if session history nil. if so, returns current history on file , loads file history property. otherwise, creates new empty session history. after that, or if history property stores something, returns history property.
usage
all setup nscoding , nskeyedarchiver done. how use code?
each time want access session history, call
sessionhistory.apphistory() wherever want save session history, call
nskeyedarchiver.archiverootobject(sessionhistory.apphistory(), tofile: sessionhistory.datapath) sample usage work this:
let session = session(date: somerandomdate, score: somerandomscore) sessionhistory.apphistory().sessions.append(session) nskeyedarchiver.archiverootobject(sessionhistory.apphistory(), tofile: sessionhistory.datapath) the session history automatically loaded file when accessed via sessionhistory.apphistory().
you don't need "link" classes per se, need append sessions sessions array of session history.
further reading
- nshipster good, simple introduction
nscoding. - apple's nscoding guide, although older , in objective-c, goes deeper
nscoding.
Comments
Post a Comment