ios - Swift:NSKeyedArchiver 错误

标签 ios swift nsuserdefaults nscoding nskeyedarchiver

Swift 3 iOS 10,尝试在 NSKeyedArchiver 中保存带有自定义对象的数组,基本上是在用户使用按钮在各部分之间切换后尝试保存表格 View 。我已经尝试了几个帖子来解决这个问题,但没有成功,现在我正在尝试自己做 NSCoding 和 NSKeyedArchiver。

错误:

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

错误在 Blog.swift 的代码中,处理 NSCoding 的代码和我的博客对象

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")
 }

}

在 MainController.swift 中——我的 tableview 在哪里

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?
    }
}

跟随按钮

// 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")
        }
}

从服务器接收数据

// 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)")
    }

另外,“路径”的定义和使用是否正确?谢谢!

最佳答案

NSCoding 的目的是将类的每个属性转换为符合属性列表的格式。

首先将所有 String 属性声明为非可选的,因为自定义初始化程序仅传递非可选参数。

然后在init(coderencode(with 方法(edited)

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")
    }
}

但是有一个潜在的警告:

编码/解码目标类的对象数组可能会导致意外行为,例如无限循环。考虑一下。您可以单独对数组进行编码。


第二个问题是打字错误,您将 "path" 作为文字字符串而不是变量 path 传递:

NSKeyedArchiver.archiveRootObject(mainArray, toFile: path)

关于ios - Swift:NSKeyedArchiver 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44481054/

相关文章:

ios - UICollectionElementKindCell 的 registerNib 在使用 presentViewController 动画时不起作用 : false

ios - 测试 userDefaults 和私有(private)函数

ios - 为什么约束不起作用?

ios - 创建子类并覆盖 loadView() 时 UITableViewController.tableView=nil

swift - AVCaptureVideoDataOutput captureOutput 未被调用

ios - 如何使用完成处理程序方法运行 for 循环?

ios - 使用 NSUserDefaults 保存静态表格 View 单元格复选标记

ios - NSUserDefaults 创建全局可访问的变量

ios - 如何在 swift 中将 touchUpInside 函数作为参数传递?

ios - 在 swift 中使用 SWReveal 设置 Root View Controller 时出错