Swift: self.init (coder : aDecoder) is crashing app with EXC_BAD_ACCESS

徘徊边缘 提交于 2020-01-17 06:46:35

问题


Error is crashing app when using NSCoder and NSKeyArchiver.

I had made a recent post around NSCoder but since then I've changed my code around and got a new error and decided a new post is best.

The app is a blog reader, reading from a MYSQL database using PHP to fill a table view with custom objects in Swift using JSON. I've been trying to save mainArray so that when the user moves cells across sections (each section has an array) it can save where the user left it.

Blog.swift: Handles the Blogs custom objects

import UIKit

class Blog: NSObject, NSCoding {

var blogName: String!
var blogStatus1: String!
var blogStatus2: String!
var blogURL: String!
var blogID: String!
var blogType: String!
var blogDate: String!
var blogPop: String!

static func createBlog(from jsonObject: AnyObject) -> Blog? {

    guard let bID: String = jsonObject.object(forKey: "id") as? String,
        let bName: String = jsonObject.object(forKey: "blogName") as? String,
        let bStatus1: String = jsonObject.object(forKey: "blogStatus1") as? String,
        let bStatus2: String = jsonObject.object(forKey: "blogStatus2") as? String,
        let bURL: String = jsonObject.object(forKey: "blogURL") as? String,
        let bType: String = jsonObject.object(forKey: "blogType") as? String,
        let bDate: String = jsonObject.object(forKey: "blogDate") as? String,
        let bPop: String = jsonObject.object(forKey: "blogPop") as? String

        else {
          print("Error: (Creating Blog Object)")
          return nil
 }

let blog = Blog()
    blog.blogName = bName
    blog.blogStatus1 = bStatus1
    blog.blogStatus2 = bStatus2
    blog.blogURL = bURL
    blog.blogID = bID
    blog.blogType = bType
    blog.blogDate = bDate
    blog.blogPop = bPop
    return blog
 }

// NSCoding
convenience required init?(coder aDecoder: NSCoder) {
    self.init (coder : aDecoder) // *** Crashes Here ***
    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
 }

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

MainController.swift - Where table view is located

var mainArray = [Blog]()
var followedArray = [Blog]()

override func viewDidLoad() {
    super.viewDidLoad()

    // Receiving Data from Server
    retrieveData()

    if let data = UserDefaults.standard.data(forKey: "mainArrayKey"),
        let myBlogList = NSKeyedUnarchiver.unarchiveObject(with: data) as? [Blog] {
        mainArray = myBlogList
        print("mainArray: \(mainArray)")
    } else {
        print("Error: (Saving to UserDefaults)")
    }
}

// Retrieving Data from Server
func retrieveData() {

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

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

        // Looping through jsonArray
        for jsonObject in jsonArray {
            if let blog = Blog.createBlog(from: jsonObject as AnyObject) {
                mainArray.append(blog)

                // Save to UserDefaults
                let encodedData = NSKeyedArchiver.archivedData(withRootObject: mainArray)
                UserDefaults.standard.set(encodedData, forKey: "mainArrayKey")
            }
        }
    }
    catch {
        print("Error: (Retrieving Data)")
    }
    myTableView.reloadData()

    // Logs
    print("This is mainArray", mainArray)

    // Check UserDefaults
    if UserDefaults.standard.object(forKey: "mainArrayKey") != nil{
        print("mainArray key exists")
    }
    else {
        print("mainArray key does not exist")
    }
}

回答1:


Looks like an infinite loop to me. You call init(coder:), and the first line calls init(coder:), and the first line calls init(coder:), and so on ad infinitum.

You need to call a different initializer inside it. Try self.init() instead.




回答2:


As others have stated it's indeed an infinite loop. What you need to do is change it to self.init() and also add in the following to your code. Or implement your own init that does whatever needs to be done.

override init() {
    super.init()
 }


来源:https://stackoverflow.com/questions/44531300/swift-self-init-coder-adecoder-is-crashing-app-with-exc-bad-access

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!