Swift NSCoder NSKeyArchiver:解包时意外发现 nil
Swift NSCoder NSKeyArchiver: unexpectedly found nil while unwrapping
使用 NSCoder 从 json.
中归档数组中的自定义对象时出错导致崩溃
导致崩溃的错误:
fatal error: unexpectedly found nil while unwrapping an Optional value
错误代码:我在 retrieveData() 中包含了完整代码
// NSCoding *Error causes Crash here*
let blogList: NSObject = ((jsonArray[i]) as! NSObject).value(forKey: "blogList") as! NSObject
MainController.swift
// Retrieving Data from Server *Clean Code*
func retrieveData() {
let getDataURL = "http://blogtest.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
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 *Error causes Crash here*
let blogList: NSObject = ((jsonArray[i]) as! NSObject).value(forKey: "blogList") as! NSObject
// Add Blog Objects to mainArray
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)")
}
myTableView.reloadData()
}
Blog.swift - 处理博客自定义对象
import UIKit
class Blog: NSObject, 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] // 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 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 // NSCoding
super.init()
}
// NSCoding
convenience required init?(coder aDecoder: NSCoder) {
self.init (coder : aDecoder)
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]
}
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")
}
}
此次崩溃与NSCoder无关。检查调试器或记录 value(forKey: "blogList") 的值。它很可能不存在。你能给出你在网络响应中得到的响应示例吗?
此外,我建议不要使用强制解包,而是使用带有保护的可选,因为服务器响应不可信任,这可能会在将来开始导致崩溃
您应该将构造函数更改为以下内容
init?(id:String, info:[String:AnyObject]){
guard let name = info["blogName"] as? String, let blogStatus1 = info["blogStatus1"] as? String ... so on .. else {
return nil
}
blogName = name
.
. initialize all field like these
// for blog list
var tmpBlogList = [BlogList]()
if let tmpBlogListInfo = info["blogList"] as? [[String:AnyObject]]
{
for info in tmpBlogListInfo
{
let childId = info["blogID"] as? String
if let blog = Blog(id:childId, info) {
tmpBlogList.append(blog)
}
}
}
blogList = tmpBlogList
}
//Replace mainArray.append(Blog(blogName: bName, andBlogStatus1: bStatus1, andBlogStatus2: bStatus2, andBlogURL: bURL, andBlogID: bID, andBlogType: bType, andBlogDate: bDate, andBlogPop: bPop, blogList: blogList as! [Blog]))
if let blog = Blog(id: bID, info: blogList) {
mainArray.append(blog)
}
使用 NSCoder 从 json.
中归档数组中的自定义对象时出错导致崩溃导致崩溃的错误:
fatal error: unexpectedly found nil while unwrapping an Optional value
错误代码:我在 retrieveData() 中包含了完整代码
// NSCoding *Error causes Crash here*
let blogList: NSObject = ((jsonArray[i]) as! NSObject).value(forKey: "blogList") as! NSObject
MainController.swift
// Retrieving Data from Server *Clean Code*
func retrieveData() {
let getDataURL = "http://blogtest.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
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 *Error causes Crash here*
let blogList: NSObject = ((jsonArray[i]) as! NSObject).value(forKey: "blogList") as! NSObject
// Add Blog Objects to mainArray
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)")
}
myTableView.reloadData()
}
Blog.swift - 处理博客自定义对象
import UIKit
class Blog: NSObject, 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] // 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 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 // NSCoding
super.init()
}
// NSCoding
convenience required init?(coder aDecoder: NSCoder) {
self.init (coder : aDecoder)
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]
}
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")
}
}
此次崩溃与NSCoder无关。检查调试器或记录 value(forKey: "blogList") 的值。它很可能不存在。你能给出你在网络响应中得到的响应示例吗?
此外,我建议不要使用强制解包,而是使用带有保护的可选,因为服务器响应不可信任,这可能会在将来开始导致崩溃
您应该将构造函数更改为以下内容
init?(id:String, info:[String:AnyObject]){
guard let name = info["blogName"] as? String, let blogStatus1 = info["blogStatus1"] as? String ... so on .. else {
return nil
}
blogName = name
.
. initialize all field like these
// for blog list
var tmpBlogList = [BlogList]()
if let tmpBlogListInfo = info["blogList"] as? [[String:AnyObject]]
{
for info in tmpBlogListInfo
{
let childId = info["blogID"] as? String
if let blog = Blog(id:childId, info) {
tmpBlogList.append(blog)
}
}
}
blogList = tmpBlogList
}
//Replace mainArray.append(Blog(blogName: bName, andBlogStatus1: bStatus1, andBlogStatus2: bStatus2, andBlogURL: bURL, andBlogID: bID, andBlogType: bType, andBlogDate: bDate, andBlogPop: bPop, blogList: blogList as! [Blog]))
if let blog = Blog(id: bID, info: blogList) {
mainArray.append(blog)
}