2016-05-17 6 views
0

Ich arbeite an meiner ersten Swift iOS App, die Probleme beim Serialisieren und Speichern eines Objekts hat, dessen JSON ich vom Server abrufe. Ich benutze Gloss, eine leichte JSON-Parsing-Bibliothek, die ein Decodable-Protokoll definiert, durch das eine Instanz von JSON instanziiert werden kann. Meine Absicht ist, eine Sache von JSON (ein Typalias für [String : AnyObject]) zu laden, indem ich zuerst seine Identifikation entziehe, und dann überprüfe, ob ich bereits eine lokale archivierte Kopie habe. Wenn ich das tue, entpacke das und erhalte das Bild. Falls nicht, führen Sie eine asynchrone Anfrage für die Image-Datei durch. Das Problem ist, dass Thing.localArchiveExists(id) immer false zurückgibt. Die Objekte werden erfolgreich instanziiert, aber sie rufen das Bild immer erneut ab. Ich habe das Dateisystem überprüft und bestätigt, dass keine Archivdateien geschrieben werden. Allerdings sehe ich nicht "Fehler. Konnte nicht archivieren", was mir vorschlägt, dass die Speicherung erfolgreich war. Fehle ich etwas über das Archivieren und Speichern von NSCoder-Objekten? Vielen Dank!Versuch, eine Instanz einer Klasse zu archivieren, die NSCoder entspricht

Hier ist meine Umsetzung des Dekodierbare Protokoll:

// MARK: Decodable protocol 
// When a thing is loaded from JSON, we load its image from archive if possible. 
required init?(json: JSON) { 
    guard let id: Int = "id" <~~ json else { return nil} 

    if Thing.localArchiveExists(id) { 
     guard let savedThing = NSKeyedUnarchiver.unarchiveObjectWithFile(Thing.archiveFilePath(id)) as? Thing else { return nil } 
     self.id = savedThing.id 
     self.name = savedThing.name 
     self.image = savedThing.image 
     self.imageUrl = savedThing.imageUrl 
     super.init() 
     print("Loaded Thing \(self.name) from archive") 
    } 
    else { 
     guard let name: String = "name" <~~ json else { return nil} 
     guard let imageUrl: NSURL = "url" <~~ json else { return nil} 
     self.id = id 
     self.name = name 
     self.imageUrl = imageUrl 
     super.init() 
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { 
      let data = NSData(contentsOfURL: imageUrl) 
      dispatch_async(dispatch_get_main_queue(), { 
       self.image = UIImage(data: data!) 
       guard self.save() else { 
        print("ERROR. Could not archive") 
        return 
       } 
       print("Loaded Thing \(self.name) from server") 
      }) 
     } 
    } 
} 

Hier sind relevante Teile der Sache Klasse:

// MARK: Properties 
var id: Int? 
var name: String 
var imageUrl: NSURL? 
var image: UIImage? 

// MARK: Archiving Paths 
static let DocumentsDirectory = NSFileManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first! 
static let ArchiveURL = DocumentsDirectory.URLByAppendingPathComponent("things") 

// MARK: Types 
struct PropertyKey { 
    static let nameKey = "name" 
    static let imageKey = "image" 
    static let imageUrlKey = "imageUrl" 
    static let idKey = "id" 
} 

// Returns the file URL at which a Thing with the given ID should be saved. 
class func archiveFilePath(id: Int) -> String { 
    return Thing.ArchiveURL.URLByAppendingPathComponent("thing\(id)").absoluteString 
} 

// Checks whether an archived copy of a Thing with the given ID exists. 
class func localArchiveExists(id: Int) -> Bool { 
    let fileManager = NSFileManager.defaultManager() 
    return fileManager.fileExistsAtPath(Thing.archiveFilePath(id)) 
} 

// MARK: NSCoding 
func encodeWithCoder(coder: NSCoder) { 
    coder.encodeObject(name, forKey: PropertyKey.nameKey) 
    if image != nil { 
     coder.encodeObject(image!, forKey: PropertyKey.imageKey) 
    } 
    if imageUrl != nil { 
     coder.encodeObject(imageUrl!, forKey: PropertyKey.imageUrlKey) 
    } 
    coder.encodeInteger(id!, forKey: PropertyKey.idKey) 
} 

required convenience init?(coder aDecoder: NSCoder) { 
    let name = aDecoder.decodeObjectForKey(PropertyKey.nameKey) as! String 
    let image = aDecoder.decodeObjectForKey(PropertyKey.imageKey) as? UIImage 
    let imageUrl = aDecoder.decodeObjectForKey(PropertyKey.imageUrlKey) as? NSURL 
    let id = aDecoder.decodeIntegerForKey(PropertyKey.idKey) 

    // Must call designated initializer. 
    self.init(name: name, image: image, imageUrl: imageUrl, id: id) 
} 

func save() -> Bool {   
    // For some reason I can't archive to file. 
    return NSKeyedArchiver.archiveRootObject(self, toFile: Thing.archiveFilePath(self.id!)) 
} 
+1

... vermutlich 'Thing' erklärt seine Übereinstimmung mit' NSCoding'? – Tommy

+0

Das Problem ist die Struktur innerhalb Ihrer Klasse. Es ist nicht kompatibel mit Kodierung –

+0

@Tommy, ja, Thing wird erklärt: 'Klasse Thing: NSObject, NSCoding, Glossy {' – cproctor

Antwort

0

ich mein Problem herausgefunden: die gescheiterte sparen, weil ich noch nicht hatte Ich habe das Verzeichnis erstellt, in dem ich mein Ding speichern wollte.

func save() -> Bool {   
    let archivedData = NSKeyedArchiver.archivedDataWithRootObject(self) 
    do { 
     try NSFileManager.defaultManager().createDirectoryAtURL(Thing.ArchiveURL, withIntermediateDirectories: true, attributes: [:]) 
     try archivedData.writeToFile(Thing.archiveFilePath(self.id!), options: []) 
     return true 
    } catch { 
     print(error) 
     return false 
    } 
} 
Verwandte Themen