JSON序列化错误

时间:2017-02-11 08:28:42

标签: ios json swift

我从生成json数组的php脚本中提取数据。 iOS更新后,我的jsonserialization崩溃了应用程序。 json应该根据jsonformatter.org和freeformatter.com/json-validator.html(符合RFC4627)很好地形成。 这是代码。非常感谢任何帮助!

func parseJSON() {

    var jsonResult: NSMutableArray = NSMutableArray()

    do{
        jsonResult = try JSONSerialization.jsonObject(with: self.data as Data, options:JSONSerialization.ReadingOptions.allowFragments) as! NSMutableArray

    } catch let error as NSError {
        print(error)

    }

    var jsonElement: NSDictionary = NSDictionary()
    let locations: NSMutableArray = NSMutableArray()

    for i in 0 ..< jsonResult.count
    {

        jsonElement = jsonResult[i] as! NSDictionary

        let location = LocationModel()

        //the following insures none of the JsonElement values are nil through optional binding
        if let id = jsonElement["id"] as? String,
            let oprettelsesdato = jsonElement["oprettelsesdato"] as? String,
            let overskrift = jsonElement["overskrift"] as? String,
            let address = jsonElement["address"] as? String,
            let intro = jsonElement["intro"] as? String,
            let email = jsonElement["email"] as? String,
            let tlf = jsonElement["tlf"] as? String,
            let annonce = jsonElement["annonce"] as? String,
            let journalnr = jsonElement["journal"] as? String
        {

            location.id = id
            location.oprettelsesdato = oprettelsesdato
            location.overskrift = overskrift
            location.address = address
            location.intro = intro
            location.email = email
            location.tlf = tlf
            location.annonce = annonce
            location.journalnr = journalnr


        }

        locations.add(location)

    }

    DispatchQueue.main.async(execute: { () -> Void in
        //print("Check home")
        self.delegate.itemsDownloaded(locations)

    })
}

崩溃日志:

objc[1285]: Class PLBuildVersion is implemented in both /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/PrivateFrameworks/AssetsLibraryServices.framework/AssetsLibraryServices (0x11799a998) and /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/PrivateFrameworks/PhotoLibraryServices.framework/PhotoLibraryServices (0x1177bc880). One of the two will be used. Which one is undefined.
Could not cast value of type '__NSArrayI' (0x105f1ed88) to 'NSMutableArray' (0x105f1ee50).

更新 我现在使用vadians解决方案,但是,我使用self.delegate.itemsDownloaded(位置为NSArray)而不是self.delegate.itemsDownloaded(位置)。

然而,所有jsonElements现在都是零。它获得了数组中正确数量的元素,但是如果我打印它,则所有值都是nil:

(
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil",
"id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil"
)

这是我尝试检索数据的地方。

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let item: LocationModel = feedItems[indexPath.row] as! LocationModel
    let cellIdentifier: String = "BasicCell"
    let myCell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!



    //myCell.detailTextLabel!.text = item.oprettelsesdato
    myCell.textLabel!.text = item.overskrift
    myCell.textLabel!.leadingAnchor.constraint(equalTo: myCell.leadingAnchor).isActive = true
    myCell.textLabel!.topAnchor.constraint(equalTo: myCell.topAnchor).isActive = true
    myCell.textLabel!.heightAnchor.constraint(equalTo: myCell.heightAnchor,
                                                multiplier: 1.0).isActive = true
    myCell.textLabel!.widthAnchor.constraint(equalTo: myCell.heightAnchor,
                                                multiplier: 0.8).isActive = true


    //print(item.id)  <-returns nil
    //print(item.oprettelsesdato)  <-returns nil
    //print(item.overskrift)  <-returns nil
    extralabel!.text = item.oprettelsesdato  // <-This is where the error is thrown
    extralabel!.textColor =  UIColor.white
    myCell.contentView.addSubview(extralabel!)

//some more stuff...
}

错误:

fatal error: unexpectedly found nil while unwrapping an Optional value

不确定出了什么问题。有什么建议吗?

3 个答案:

答案 0 :(得分:3)

请允许我重复我的评论:

不要 - 永远 - 在Swift中使用NSMutable...集合类型。

它们与Swift集合类型无关并导致所有问题。 var关键字使任何Swift对象都可变,非常容易使用。除此之外,您的代码中的接收数组根本没有变异。

可悲的是,建议NSMutable...半知识教程永远不会消亡:/

在Swift 3中

  • JSON字典是[String:Any]
  • JSON数组是[[String:Any]][Any]

由于JSON对象应该是一个数组.allowframents,因此很无用。

所以:

func parseJSON() {

    var jsonResult = [[String:Any]]()

    do{
        jsonResult = try JSONSerialization.jsonObject(with: self.data as Data, options:[]) as! [[String:Any]]

    } catch {
        print(error)
        return
    }

    var locations = [LocationModel]()

    for jsonElement in jsonResult { // no ugly C-style index based loops!

        let location = LocationModel()

        //the following insures none of the JsonElement values are nil through optional binding
        if let id = jsonElement["id"] as? String,
            let oprettelsesdato = jsonElement["oprettelsesdato"] as? String,
            let overskrift = jsonElement["overskrift"] as? String,
            let address = jsonElement["address"] as? String,
            let intro = jsonElement["intro"] as? String,
            let email = jsonElement["email"] as? String,
            let tlf = jsonElement["tlf"] as? String,
            let annonce = jsonElement["annonce"] as? String,
            let journalnr = jsonElement["journal"] as? String
        {

            location.id = id
            location.oprettelsesdato = oprettelsesdato
            location.overskrift = overskrift
            location.address = address
            location.intro = intro
            location.email = email
            location.tlf = tlf
            location.annonce = annonce
            location.journalnr = journalnr


        }

        locations.append(location)

    }

    DispatchQueue.main.async {
        //print("Check home")
        self.delegate.itemsDownloaded(locations)
    }
}

注意:如果jsonElement只包含字符串,您甚至可以将字典转换为[String:String]并删除所有 as? String强制转换。

答案 1 :(得分:2)

我建议创建一个可选的init方法,该方法接受json并尝试创建LocationModel

struct LocationModel {

    var id: String
    var oprettelsesdato: String
    var overskrift: String
    var address: String
    var intro: String
    var email: String
    var tlf: String
    var annonce: String
    var journalnr: String

    init?(json: [String:Any]) {

        guard
            let id = json["id"] as? String,
            let oprettelsesdato = json["oprettelsesdato"] as? String,
            let overskrift = json["overskrift"] as? String,
            let address = json["address"] as? String,
            let intro = json["intro"] as? String,
            let email = json["email"] as? String,
            let tlf = json["tlf"] as? String,
            let annonce = json["annonce"] as? String,
            let journalnr = json["journal"] as? String else { return }

        self.id = id
        self.oprettelsesdato = oprettelsesdato
        self.overskrift = overskrift
        self.address = address
        self.intro = intro
        self.email = email
        self.tlf = tlf
        self.annonce = annonce
        self.journalnr = journalnr
    }
}

然后,在parseJSON函数中,您可以使用NSMutableArray而不是[LocationModel]。这样我们就可以使用flatMap直接[[String:Any]] json元素数组([LocationModel])到json.flatMap { LocationModel(json: $0) }

func parseJSON() {

    var locations = [LocationModel]()

    do{
        if let json = try JSONSerialization.jsonObject(with: data as Data, options: []) as? [[String:Any]] {
            locations = json.flatMap { LocationModel(json: $0) }
        }
    } catch let error as NSError {
        print(error)
    }

    DispatchQueue.main.async {
        self.delegate.itemsDownloaded(locations)
    }
}

答案 2 :(得分:1)

对于您的问题至关重要的是这一部分as! NSMutableArray

jsonResult = try JSONSerialization.jsonObject(with: self.data as Data, options:JSONSerialization.ReadingOptions.allowFragments) as! NSMutableArray

即使在较旧的iOS中,将NSJSONSerialization.JSONObjectWithData的结果转换为NSMutableArray 也不是保证操作(当您未指定{{1}时}选项)。

看到您的整个代码,您不会改变.mutableContainers,因此您可以使用简单的jsonResult而不是NSArray

NSMutableArray

我建议您使用Swift类型,例如 var jsonResult: NSArray = NSArray() do{ jsonResult = try JSONSerialization.jsonObject(with: self.data as Data) as! NSArray } catch let error as NSError { print(error) } DataArray,而不是DictionaryNSDataNSArray )或NSMutableArray。但这对你的情况并不重要。