简体   繁体   中英

Swift JSON with Alamofire - Unexpectedly found nil while unwrapping an Optional value

I'm trying to parse a JSON in my app and it's not working. Here is a look at the JSON I'm trying to parse:

JSON格式

Check out the following screenshots. I get the error "Unexpectedly found nil while unwrapping an optional value" on the line

editorialElement.title = nodeElement!.valueForKey("title") as! String

第1部分 第2部分

Can anyone help me properly parse this JSON ?

EDIT 1: Here is more code. It shows what class I'm using (ie what objects I am creating based on the JSON file). I imagine this is what you meant by where I initialize JSON objects.

类定义

Here is my router as well (build using Alamofire). I feel like something might be wrong with it but at the same time, it makes a lot of sense and I don't know what missing: 路由器

EDIT 2: Here is the actual code:

func populateEditorials() {
    if populatingEditorials {
        return
    }

    populatingEditorials = true


    Alamofire.request(GWNetworking.Router.Editorials(self.currentPage)).responseJSON() { response in
        if let JSON = response.result.value {
           /*
        if response.result.error == nil {
            */

            /* Creating objects for every single editorial is long running work, so we put that work on a background queue, to keep the app very responsive. */
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {

                /*
                // Making an array of all the node IDs from the JSON file
                let nodeIDArray : [String]
                var nodeCounter : Int = 0 */


                for node in JSON as! NSDictionary {

                    var nodeElement = JSON.valueForKey(String(node))

                    self.nodeIDArray.addObject(String(node.key))

                    var editorialElement : EditorialElement = EditorialElement(title: "init", nodeID: 0, timeStamp: 0, imageURL: "init", author: "init", issueNumber: "init", volumeNumber: "init", articleContent: "init")

                editorialElement.title = nodeElement!.valueForKey("title") as! String
                editorialElement.nodeID = nodeElement!.valueForKey("nid") as! Int
                editorialElement.timeStamp = nodeElement!.valueForKey("revision_timestamp") as! Int
                editorialElement.imageURL = nodeElement!.valueForKey("image_url") as! String
                editorialElement.author = nodeElement!.valueForKey("author") as! String
                editorialElement.issueNumber = nodeElement!.valueForKey("issue_int") as! String
                editorialElement.volumeNumber = nodeElement!.valueForKey("volume_int") as! String
                editorialElement.articleContent = nodeElement!.valueForKey("html_content") as! String

                self.editorialObjects.addObject(editorialElement)


/*

                        nodeIDArray[nodeCounter] = jsonValue{nodeCounter}.string
                        let editorialInfos : EditorialElement = ((jsonValue as! NSDictionary).valueForKey("\(nodeIDArray[nodeCounter])") as! [NSDictionary]).map { EditorialElement(title: $0["title"] as! String, nodeID: $0["nid"] as! Int, timeStamp: $0["revision_timestamp"] as! Int, imageURL: $0["image_url"] as! String, author: $0["author"], issueNumber: $0["issue_int"] as! Int, volumeNumber: $0["volume_int"] as! Int, articleContent: $0["html_content"] as! String) /* I am going to try to break this line down to simplify it and fix the build errors */
*/


}

                print(self.editorialObjects)

            }


            /* Sorting the elements in order of newest to oldest (as the array index increases) */
            self.editorialObjects.sort({ $0.timeStamp > $1.timeStamp })


                let lastItem = self.editorialObjects.count

                let indexPaths = (lastItem..<self.editorialObjects.count).map { NSIndexPath(forItem: $0, inSection: $0) }

                dispatch_async(dispatch_get_main_queue()) {
                    self.editorialsTableView.insertRowsAtIndexPaths(indexPaths, withRowAnimation: UITableViewRowAnimation.Automatic) // Animation implemented for testing, to be removed for version 1.0
                }

                self.currentPage++
/*                } */
        }

        self.populatingEditorials = false

    }

}

Here is the code for my Class and Router:

class EditorialElement: NSObject {

var title: String           // title
var nodeID: Int             // nid
var timeStamp: Int       // revision_timestamp
var imageURL: String?       // image_url
var author: String          // author

var issueNumber: String     // issue_int
var volumeNumber: String    // volume_int

var articleContent: String // html_content

/* To get an NSDate objec from Unix timestamp
var date = NSDate(timeIntervalSince1970: timeStamp) */

init(title: String, nodeID: Int, timeStamp: Int, imageURL: String, author: String, issueNumber: String, volumeNumber: String, articleContent: String) {
    self.title = title
    self.nodeID = nodeID
    self.timeStamp = timeStamp
    self.imageURL = imageURL
    self.author = author
    self.issueNumber = issueNumber
    self.volumeNumber = volumeNumber
    self.articleContent = articleContent
}

override func isEqual(object: AnyObject!) -> Bool {
    return (object as! EditorialElement).nodeID == self.nodeID
}

override var hash: Int {
    return (self as EditorialElement).nodeID
}

}



enum Router : URLRequestConvertible {
static let baseURLString = MyGlobalVariables.baseURL

case Issue
case Editorials(Int)
case News(Int)
case Random(Int)
case Pictures(Int)

var URLRequest: NSMutableURLRequest {
    let path : String
    let parameters: [String: AnyObject]
    (path) = {
        switch self {
        case .Issue:
            return ("/issue")
        case .Editorials (let editorialsSection): /* If section == 0, this will return the first ten editorials. If section == 1, then section * 10 = 10, and we will get the ten editorials after that. */
            return ("/list/editorials/\(editorialsSection * 10)")
        case .News (let newsSection):
            return ("/list/news/\(newsSection * 10)")
        case .Random (let randomSection):
            return ("/list/random/\(randomSection * 10)")
        case .Pictures (let page):
            return ("/list/pictures/\(page)")


        }
    }()

    let URL = NSURL(string: Router.baseURLString)
    let GoldenWordsURLRequest = NSMutableURLRequest(URL: URL!.URLByAppendingPathComponent(path))
/*        let encoding = Alamofire.ParameterEncoding.URL */



    return GoldenWordsURLRequest
/*        return encoding.encode(URLRequest, parameters: parameters).0 */

    }
}
}

That's because you take an optional reference ( editorialElement returned from a failable initializer) and call valueForKey("title") on it. It stumbles over the access to "title" because it goes first in you code while the target of the call is nil. I would recommend organizing your code as follows:

if let editorialElement = EditorialElement(title:..., nodeID: and such)
{
   ... assigning new values to the properties
}

and you will notice that you don't enter the if-let scope. You will avoid the crash and make sure the problem is inside the arguments you initialize the editorialElement with.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM