ios - How to save a generic custom object to UserDefaults? -


this generic class:

open class smstate<t: hashable>: nsobject, nscoding {     open var value: t      open var didenter: ( (_ state: smstate<t>) -> void)?     open var didexit:  ( (_ state: smstate<t>) -> void)?      public init(_ value: t) {         self.value = value     }      convenience required public init(coder decoder: nscoder) {         let value = decoder.decodeobject(forkey: "value") as! t          self.init(value)     }      public func encode(with acoder: nscoder) {         acoder.encode(value, forkey: "value")     } } 

then want this:

    let stateencodedata = nskeyedarchiver.archiveddata(withrootobject: currentstate)     userdefaults.standard.set(stateencodedata, forkey: "state") 

in case currentstate of type smstate<someenum>.

but when call nskeyedarchiver.archiveddata, xcode (9 beta 5) shows message in purple saying:

attempting archive generic swift class 'stepup.smstate<stepup.routineviewcontroller.routinestate>' mangled runtime name '_ttgc6stepup7smstateocs_21routineviewcontroller12routinestate_'. runtime names generic classes unstable , may change in future, leading non-decodable data. 

i not sure tries say. not possible save generic object ?

is there other way save generic custom object ?

edit:

even if use anyhashable instead of generics same error on runtime when calling nskeyedarchiver.archiveddata:

terminating app due uncaught exception 'nsinvalidargumentexception', reason: : unrecognized selector sent instance 

if want make generic class adopt nscoding , generic type t going encoded , decoded t must 1 of property list compliant types.

property list compliant types nsstring, nsnumber, nsdate , nsdata


a possible solution create protocol propertylistable , extend swift equivalents of property list compliant types protocol

the protocol requirements

  • an associated type.
  • a computed property propertylistrepresentation convert value property list compliant type.
  • an initializer init(propertylist contrary.

public protocol propertylistable {     associatedtype propertylisttype     var propertylistrepresentation : propertylisttype { }     init(propertylist : propertylisttype) } 

here exemplary implementations string , int.

extension string : propertylistable {     public typealias propertylisttype = string     public var propertylistrepresentation : propertylisttype { return self }     public init(propertylist: propertylisttype) { self.init(stringliteral: propertylist) } }  extension int : propertylistable {     public typealias propertylisttype = int     public var propertylistrepresentation : propertylisttype { return self }     public init(propertylist: propertylisttype) { self.init(propertylist) } } 

lets declare sample enum , adopt propertylistable

enum foo : int, propertylistable {     public typealias propertylisttype = int      case north, east, south, west      public var propertylistrepresentation : propertylisttype { return self.rawvalue }     public init(propertylist: propertylisttype) {         self.init(rawvalue:  propertylist)!     } } 

finally replace generic class

open class smstate<t: propertylistable>: nsobject, nscoding {     open var value: t      open var didenter: ( (_ state: smstate<t>) -> void)?     open var didexit:  ( (_ state: smstate<t>) -> void)?      public init(_ value: t) {         self.value = value     }      convenience required public init(coder decoder: nscoder) {         let value = decoder.decodeobject(forkey: "value") as! t.propertylisttype         self.init(t(propertylist: value))     }      public func encode(with acoder: nscoder) {         acoder.encode(value.propertylistrepresentation, forkey: "value")     } } 

with implementation can create instance , archive it

let currentstate = smstate<foo>(foo.north) let stateencodedata = nskeyedarchiver.archiveddata(withrootobject: currentstate) 

and unarchive again

let restoredstate = nskeyedunarchiver.unarchiveobject(with: stateencodedata) as! smstate<foo> print(restoredstate.value) 

the whole solution seems cumbersome have fulfill restriction nscoding requires property list compliant types. if don't need custom type enum implementation easier (and shorter).


Comments

Popular posts from this blog

Is there a better way to structure post methods in Class Based Views -

performance - Why is XCHG reg, reg a 3 micro-op instruction on modern Intel architectures? -

jquery - Responsive Navbar with Sub Navbar -