Swift:NSKeyedArchiver 中的错误 [英] Swift: Error in NSKeyedArchiver
问题描述
Swift 3 iOS 10,尝试在 NSKeyedArchiver 中使用自定义对象保存数组,基本上是在用户使用按钮在部分之间切换后尝试保存表格视图.我已经尝试了几个帖子来解决这个问题,但没有运气,现在我正在尝试自己做 NSCoding 和 NSKeyedArchiver.
Swift 3 iOS 10, Trying to save array with custom objects in NSKeyedArchiver, basically trying to save the table view after the user uses the buttons to switch between sections. I've tried several post to solve the issue but no luck, now I'm trying to do it myself NSCoding and NSKeyedArchiver.
错误:
无法将类型[Blog]"的值转换为预期的参数类型NSCoder"
Cannot convert value of type '[Blog]' to expected argument type 'NSCoder'
Blog.swift 中的代码出错,处理 NSCoding 和我的博客对象的代码
Error is in code in Blog.swift, Code that handles NSCoding and my Blog Objects
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 在哪里
In MainController.swift - Where my tableview is
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)")
}
此外,路径"的定义和使用是否正确?谢谢!
Also, is 'path' defined and used right? Thank you!
推荐答案
NSCoding
的目的是将类的每个属性转换为符合属性列表的格式.
The purpose of NSCoding
is to convert each single property of the class to a property list compliant format.
首先将所有 String
属性声明为非可选属性,因为自定义初始值设定项仅传递非可选参数.
First of all declare all String
properties as non-optional because the custom initializer passes only non-optional parameters.
然后在init(coder
和encode(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")
}
}
但是有一个潜在的警告:
编码/解码目标类的对象数组可能会导致意外行为,例如无限循环.考虑一下.您可以单独对数组进行编码.
Encoding / decoding an array of objects of the target class may cause unexpected behavior for example an infinite loop. Consider that. You might encode the array separately.
第二个问题是拼写错误,您将 "path"
作为文字字符串而不是变量 path
传递:
The second issue is a typo, you pass "path"
as a literal string rather than a variable path
:
NSKeyedArchiver.archiveRootObject(mainArray, toFile: path)
这篇关于Swift:NSKeyedArchiver 中的错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!