简体   繁体   English

使用Alamofire的Swift JSON-在展开可选值时意外发现nil

[英]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. 我正在尝试在我的应用程序中解析JSON,但无法正常工作。 Here is a look at the JSON I'm trying to parse: 这是我尝试解析的JSON:

JSON格式

Check out the following screenshots. 查看以下屏幕截图。 I get the error "Unexpectedly found nil while unwrapping an optional value" on the line 我在行上收到错误“在展开可选值时意外发现nil”

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

第1部分 第2部分

Can anyone help me properly parse this JSON ? 谁能帮助我正确解析此JSON?

EDIT 1: Here is more code. 编辑1:这是更多的代码。 It shows what class I'm using (ie what objects I am creating based on the JSON file). 它显示了我正在使用的类(即我根据JSON文件创建的对象)。 I imagine this is what you meant by where I initialize JSON objects. 我想这就是初始化JSON对象的意思。

类定义

Here is my router as well (build using Alamofire). 这也是我的路由器(使用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: 编辑2:这是实际的代码:

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. 那是因为你有一个可选的参考( editorialElement从failable初始化返回),并调用valueForKey("title")就可以了。 It stumbles over the access to "title" because it goes first in you code while the target of the call is nil. 它绊倒了对“ title”的访问,因为它在您的代码中排在第一位,而调用的目标是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. 并且您会注意到您没有输入if-let范围。 You will avoid the crash and make sure the problem is inside the arguments you initialize the editorialElement with. 您将避免崩溃,并确保问题出在用于初始化editorialElement的参数内。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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