2017-05-25 4 views
0

J'ai déjà lu plusieurs articles et essayé toutes les solutions, rien ne fonctionne dans mon cas. J'utilise cette structure de données complexe et j'ai besoin de stocker un tableau de DrawnObjects dans le fichier. Mais il plante quand il s'agit d'encoder une variable qui est elle-même un tableau de type Structure. De l'aide ?Encoder objet complexe swift 3.0

[_SwiftValue encodeWithCoder:]: sélecteur non reconnu envoyé à l'instance 0x1702668c0

enum ArchiverKeys : String 
{ 
    case imageView = "ImageView" 
    case stateArray = "StateArray" 
    case bezierPathArray = "BezierPathArray" 
    case reactangleArray = "ReactangleArray" 
    case deleted = "Deleted" 
} 
    struct RectanglePath { 
     var point1: CGPoint 
     var point2: CGPoint 
     var point3: CGPoint 
     var point4: CGPoint 
    } 

    struct StateObject { 
     var isAdd = true 
     var path = String() 
    } 

    class DrawObject: NSObject , NSCoding { 

     var ImageView = UIImageView() 
     var arrStates = [StateObject]() 
     var arrBezierPaths = [UIBezierPath]() 
     var rects = [RectanglePath]() 
     var deleted = false 


     override init() { 
      ImageView = UIImageView() 
      arrStates = [] 
      arrBezierPaths = [] 
      rects = [] 
      deleted = false 
     } 

     func encode(with archiver: NSCoder) { 
      archiver.encode(self.ImageView, forKey:ArchiverKeys.imageView.rawValue) 
      archiver.encode(self.arrStates, forKey: ArchiverKeys.stateArray.rawValue) 
      archiver.encode(self.arrBezierPaths, forKey:ArchiverKeys.bezierPathArray.rawValue) 
      archiver.encode(self.rects, forKey: ArchiverKeys.reactangleArray.rawValue) 
      archiver.encode(self.deleted, forKey: ArchiverKeys.deleted.rawValue) 
     } 

     required convenience init(coder unarchiver: NSCoder) { 

      self.init() 

      self.ImageView  = unarchiver.decodeObject(forKey: ArchiverKeys.imageView.rawValue) as! UIImageView 
      self.arrStates  = unarchiver.decodeObject(forKey: ArchiverKeys.stateArray.rawValue) as! [StateObject] 
      self.arrBezierPaths = unarchiver.decodeObject(forKey: ArchiverKeys.bezierPathArray.rawValue) as! [UIBezierPath] 
      self.rects   = unarchiver.decodeObject(forKey: ArchiverKeys.reactangleArray.rawValue) as! [RectanglePath] 
      self.deleted  = (unarchiver.decodeObject(forKey: ArchiverKeys.deleted.rawValue) != nil) 
     } 
    } 

    func saveArrayTo(_ directoryName: String , arrayToSave: NSArray) { 

    // let encodedData = NSKeyedArchiver.archivedData(withRootObject: arrayToSave) 
     NSKeyedArchiver.archiveRootObject(arrayToSave, toFile: directoryName) 
    } 

    func loadArrayFrom(_ directoryName: String) -> NSArray? { 
     let result = NSKeyedUnarchiver.unarchiveObject(withFile: directoryName) 
     return result as? NSArray 
    } 

Répondre

3

Vous ne pouvez pas coder une struct Swift de la boîte, vous devez ajouter une propriété calculée et une méthode init pour faire la liste des biens struct conformes

struct StateObject { 
    var isAdd = true 
    var path = "" 

    init(propertyList : [String:Any]) { 
     self.isAdd = propertyList["isAdd"] as! Bool 
     self.path = propertyList["path"] as! String 
    } 

    var propertyListRepresentation : [String:Any] { 
     return ["isAdd" : isAdd, "path" : path] 
    } 
} 

maintenant, vous pouvez archiver le tableau

archiver.encode(self.arrStates.map{$0.propertyListRepresentation}, forKey: ArchiverKeys.stateArray.rawValue) 

et désarchiver

let states = unarchiver.decodeObject(forKey: ArchiverKeys.stateArray.rawValue) as! [[String:Any]] 
self.arrStates = states.map { StateObject(propertyList: $0) } 

laisser inchangé En variante StateObject et

  • en encode(with remplacer la ligne

    archiver.encode(self.arrStates, forKey: ArchiverKeys.stateArray.rawValue) 
    

    avec

    let arrStatesAsPlist = arrStates.map { return ["isAdd" : $0.isAdd, "path" : $0.path] } 
    archiver.encode(arrStatesAsPlist, forKey:ArchiverKeys.stateArray.rawValue) 
    
  • en init(coder remplacer la ligne

    archiver.encode(self.arrStates, forKey: ArchiverKeys.stateArray.rawValue) 
    

    avec

    let arrStatesAsPlist = unarchiver.decodeObject(forKey: ArchiverKeys.stateArray.rawValue) as! [[String:Any]] 
    arrStates = arrStatesAsPlist.map { StateObject(isAdd: $0["isAdd"] as! Bool, path: $0["path"] as! String) } 
    

Notes:

  • Puisque vous affectez des valeurs par défaut à toutes les propriétés, vous pouvez supprimer l'intégralité de la méthode init() et l'appel init() dans init(coder. Ne pas utiliser NSArray dans Swift. Utiliser un natif Array

  • Ce n'est pas une bonne idée d'archiver un élément de l'interface utilisateur comme UIImageView. Archiver les données d'image.

+0

merci @vadian je vais essayer ceci et vous le faire savoir. – ChanWarde

+0

OMG, cela a fonctionné. Merci beaucoup @vadian. Maintenant, je travaille sur pour enregistrer des images au lieu de l'image. – ChanWarde