2017-06-11 1 views
1

Swift 3 iOS 10, versucht Array mit benutzerdefinierten Objekten in NSKeyedArchiver zu speichern, grundsätzlich versucht, die Tabellenansicht zu speichern, nachdem der Benutzer die Schaltflächen verwendet, um zwischen Abschnitten zu wechseln. Ich habe mehrere Post versucht, um das Problem zu lösen, aber kein Glück, jetzt versuche ich es selbst NSCoding und NSKeyedArchiver zu tun.Swift: Fehler in NSKeyedArchiver

Fehler:

Cannot convert value of type '[Blog]' to expected argument type 'NSCoder'

Fehler ist in Code in Blog.swift, Code, der NSCoding und mein Blog Objekte

import UIKit 

class BlogsCoding: NSObject, NSCoding { 

var blogList : [Blog] 

init(blogList : [Blog]) { 
    self.blogList = blogList 
} 

convenience required init?(coder aDecoder: NSCoder) { 

    guard let blogList = aDecoder.decodeObject(forKey: "blogs") as? [Blog] 
     else { 
      return nil 
    } 
    self.init (blogList : blogList) 
} 

func encode(with aCoder: NSCoder) { 

    aCoder.encode(blogList, forKey: "blogs") 
} 
} 

class Blog: NSObject, NSCoding { // To conform to NSCoding 

// Strings 
var blogName: String? 
var blogStatus1: String? 
var blogStatus2: String? 
var blogURL: String? 
var blogID: String? 
var blogType: String? 
var blogDate: String? 
var blogPop: String? 
var blogList : [Blog] // To conform to NSCoding 

override init() { 

} 
// Converting Strings into Objects 
init(blogName bName: String, 
    andBlogStatus1 bStatus1: String, 
    andBlogStatus2 bStatus2: String, 
    andBlogURL bURL: String, 
    andBlogID bID: String, 
    andBlogType bType: String, 
    andBlogDate bDate: String, 
    andBlogPop bPop: String, 
    blogList : [Blog]) // To conform to NSCoding 
{ 
    super.init() 

    self.blogName = bName 
    self.blogStatus1 = bStatus1 
    self.blogStatus2 = bStatus2 
    self.blogURL = bURL 
    self.blogID = bID 
    self.blogType = bType 
    self.blogDate = bDate 
    self.blogPop = bPop 
    self.blogList = blogList // To conform to NSCoding 
} 

// To conform to NSCoding 
convenience required init?(coder aDecoder: NSCoder) { 

    guard let blogList = aDecoder.decodeObject(forKey: "blogs") as? [Blog] 
     else { 
      return nil 
    } 
    self.init (coder : blogList) // *---* Error is here *---* 
} 

func encode(with aCoder: NSCoder) { 

    aCoder.encode(blogList, forKey: "blogs") 
} 

} 

In MainController.swift Griffe - Wo ist mein Tableview ist

override func viewDidLoad() { 

var path : String { 
     let manager = FileManager.default 
     let url = manager.urls(for: .documentDirectory, in: .userDomainMask).first! as NSURL 
     return url.appendingPathComponent("blogs")!.path // I have a blogs.plist for this, doing it right? 
    } 
} 

Folgen Knopf

// Follow Button 
@IBAction func followButtonClick(_ sender: UIButton!) { 

// After Updating Table, Save Arrays 
     var success = false 
      // mainArray is array holding custom objects from json 
     success = NSKeyedArchiver.archiveRootObject(mainArray, toFile: "path") // If I dont use "" I get undeclared 'path' 

     if success { 
      print("Saved Blogs") 
     } else { 
      print("Didn't Save Blogs") 
     } 
} 

Daten vom Server empfangen

// Retrieving Data from Server 
func retrieveData() { 

    let getDataURL = "http://blogexample.com/receiving.php" 
    let url: NSURL = NSURL(string: getDataURL)! 

    do { 

     let data: Data = try Data(contentsOf: url as URL) 
     jsonArray = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! NSMutableArray 

     // Looping through jsonArray 
     for i in 0..<jsonArray.count { 

      // Create Blog Object 
      let bID: String = (jsonArray[i] as AnyObject).object(forKey: "id") as! String 
      let bName: String = (jsonArray[i] as AnyObject).object(forKey: "blogName") as! String 
      let bStatus1: String = (jsonArray[i] as AnyObject).object(forKey: "blogStatus1") as! String 
      let bStatus2: String = (jsonArray[i] as AnyObject).object(forKey: "blogStatus2") as! String 
      let bURL: String = (jsonArray[i] as AnyObject).object(forKey: "blogURL") as! String 
      // New 
      let bType: String = (jsonArray[i] as AnyObject).object(forKey: "blogType") as! String 
      let bDate: String = (jsonArray[i] as AnyObject).object(forKey: "blogDate") as! String 
      let bPop: String = (jsonArray[i] as AnyObject).object(forKey: "blogPop") as! String 
      // NSCoding 
      let blogList: NSObject = ((jsonArray[i]) as! NSObject).value(forKey: "blogList") as! NSObject 

      // Add Blog Objects to Main Array 
      mainArray.append(Blog(blogName: bName, andBlogStatus1: bStatus1, andBlogStatus2: bStatus2, andBlogURL: bURL, andBlogID: bID, andBlogType: bType, andBlogDate: bDate, andBlogPop: bPop, blogList: blogList as! [Blog])) 

     } 
    } 
    catch { 
     print("Error: (Retrieving Data)") 
    } 

Auch ist 'Pfad' definiert und verwendet nicht wahr? Vielen Dank!

+1

Sie Dekodieren eines Objekts '[Blog]' aber dann vorbei, das Objekt in die 'init (coder' Methode, die' NSCoder' erwartet. Das ist eine klassische Typabweichung. Btw: Deine 'reveetData()' Methode ist ziemlich hässlich. Benutze 'NSMutableArray' und' .mutableContainers' nicht result? Lassen Sie den 'options' -Parameter aus und werfen Sie das Ergebnis auf' [[String: Any]] ''. Ersetzen Sie dann die Schleife durch 'for item in jsonArray' und die Zeilen im body beispielsweise durch' let bID = item ["id"] als! String'. Das ist viel sauberer und effizienter. – vadian

+0

Wie behebe ich den Typ Mismatch, Ersetzen der BlogList mit NSCoder, gibt es den gleichen Fehler, wenn das, was Sie meinten. Für retrieveData() danke, dass ich den Code sauber machen wollte, plane ich nur, eine Tabelle mit diesen Informationen zu füllen. Wie sollte ich den Code aktualisieren? – BroSimple

+0

Die 'encoder/decoder'-Methoden dienen zum Codieren/Decodieren jeder Eigenschaft der Klasse, nicht für die Klasse selbst. – vadian

Antwort

3

Der Zweck von NSCoding besteht darin, jede einzelne Eigenschaft der Klasse in ein konformes Format der Eigenschaftenliste zu konvertieren.

Zuerst deklarieren Sie alle String Eigenschaften als nicht optional, da der benutzerdefinierte Initialisierer nur nicht optionale Parameter übergibt.

fügen Sie dann die Zeilen in den init(coder und encode(with Methoden ( bearbeitet)

class Blog: NSObject, NSCoding { // To conform to NSCoding 

    // Strings 
    var blogName: String 
    var blogStatus1: String 
    var blogStatus2: String 
    var blogURL: String 
    var blogID: String 
    var blogType: String 
    var blogDate: String 
    var blogPop: String 
    var blogList : [Blog] // To conform to NSCoding 

    // Converting Strings into Objects 
    init(blogName bName: String, 
     andBlogStatus1 bStatus1: String, 
     andBlogStatus2 bStatus2: String, 
     andBlogURL bURL: String, 
     andBlogID bID: String, 
     andBlogType bType: String, 
     andBlogDate bDate: String, 
     andBlogPop bPop: String, 
     blogList : [Blog]) // To conform to NSCoding 
    { 
     self.blogName = bName 
     self.blogStatus1 = bStatus1 
     self.blogStatus2 = bStatus2 
     self.blogURL = bURL 
     self.blogID = bID 
     self.blogType = bType 
     self.blogDate = bDate 
     self.blogPop = bPop 
     self.blogList = blogList // To conform to NSCoding 
     super.init() 
    } 

    // To conform to NSCoding 
    convenience required init?(coder aDecoder: NSCoder) { 
     self.blogName = aDecoder.decodeObject(forKey: "blogName") as! String 
     self.blogStatus1 = aDecoder.decodeObject(forKey: "blogStatus1") as! String 
     self.blogStatus2 = aDecoder.decodeObject(forKey: "blogStatus2") as! String 
     self.blogURL = aDecoder.decodeObject(forKey: "blogURL") as! String 
     self.blogID = aDecoder.decodeObject(forKey: "blogID") as! String 
     self.blogType = aDecoder.decodeObject(forKey: "blogType") as! String 
     self.blogDate = aDecoder.decodeObject(forKey: "blogDate") as! String 
     self.blogPop = aDecoder.decodeObject(forKey: "blogPop") as! String 
     self.blogList = aDecoder.decodeObject(forKey: "blogs") as! [Blog] 
     super.init (coder : aDecoder) 
    } 

    func encode(with aCoder: NSCoder) { 
     aCoder.encode(blogName, forKey: "blogName") 
     aCoder.encode(blogStatus1, forKey: "blogStatus1") 
     aCoder.encode(blogStatus2, forKey: "blogStatus2") 
     aCoder.encode(blogURL, forKey: "blogURL") 
     aCoder.encode(blogID, forKey: "blogID") 
     aCoder.encode(blogType, forKey: "blogType") 
     aCoder.encode(blogDate, forKey: "blogDate") 
     aCoder.encode(blogPop, forKey: "blogPop") 
     aCoder.encode(blogList, forKey: "blogs") 
    } 
} 

Allerdings gibt es eine potentielle Einschränkung:

Codierung/Decodierung ein Array von Objekten von der Zielklasse kann unerwartetes Verhalten zum Beispiel eine Endlosschleife verursachen. Berücksichtige das. Sie könnten das Array separat codieren.


Die zweite Ausgabe ein Tippfehler ist, übergeben Sie "path" als Zeichenkette anstatt eine Variable path:

NSKeyedArchiver.archiveRootObject(mainArray, toFile: path) 
+0

Vielen Dank für die detaillierte Antwort, keine Fehler. Was kann in der potenziellen Einschränkung in der Endlosschleife passieren, was kann das auslösen? Für 'Pfad' erhalte ich die Fehlermeldung 'Verwendung des nicht aufgelösten Bezeichners Pfad'. – BroSimple

+0

Sind Sie sicher, dass Sie eine Eigenschaft mit einem Array von Objekten der einschließenden Klasse haben möchten? Sie können die Dateierweiterung 'blogs.plist 'hinzufügen "Zum Pfad. – vadian

+0

So habe ich das Projekt erstellt und ich habe diesen Fehler" fataler Fehler: unerwartet gefunden Null beim Entpacken eines optionalen Werts "in retrieveData" least blogList: NSObject = ((jsonArray [i]) als! NSObject) .value (forKey: "blogList") als! NSObject ". Ich habe versucht, ein wenn ich aber immer noch Fehler hinzufügen. Auch, sollte ich nicht eine Eigenschaft, die Objekte enthält? Little verloren dort. Für den 'Pfad' ich die 'blogs.plist' zu" var Pfad: String "? – BroSimple

Verwandte Themen